static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
                                              USBPacket *p, uint8_t ep)
{
    /* Input interrupt endpoint, buffered packet input */
    struct buf_packet *intp, *intp_to_free;
    int status, len, sum;

    if (!dev->endpoint[EP2I(ep)].interrupt_started &&
            !dev->endpoint[EP2I(ep)].interrupt_error) {
        struct usb_redir_start_interrupt_receiving_header start_int = {
            .endpoint = ep,
        };
        /* No id, we look at the ep when receiving a status back */
        usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
                                                      &start_int);
        usbredirparser_do_write(dev->parser);
        DPRINTF("interrupt recv started ep %02X\n", ep);
        dev->endpoint[EP2I(ep)].interrupt_started = 1;
        /* We don't really want to drop interrupt packets ever, but
           having some upper limit to how much we buffer is good. */
        dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
        dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
    }

    /* check for completed interrupt message (with all fragments) */
    sum = 0;
    QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
        sum += intp->len;
        if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
            sum >= p->iov.size)
            break;
    }

    if (intp == NULL) {
        DPRINTF2("interrupt-token-in ep %02X, no intp, buffered %d\n", ep, sum);
        /* Check interrupt_error for stream errors */
        status = dev->endpoint[EP2I(ep)].interrupt_error;
        dev->endpoint[EP2I(ep)].interrupt_error = 0;
        if (status) {
            usbredir_handle_status(dev, p, status);
        } else {
            p->status = USB_RET_NAK;
        }
        return;
    }

    /* copy of completed interrupt message */
    sum = 0;
    status = usb_redir_success;
    intp_to_free = NULL;
    QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
        if (intp_to_free) {
            bufp_free(dev, intp_to_free, ep);
        }
        DPRINTF("interrupt-token-in ep %02X fragment status %d len %d\n", ep,
                intp->status, intp->len);

        sum += intp->len;
        len = intp->len;
        if (status == usb_redir_success) {
            status = intp->status;
        }
        if (sum > p->iov.size) {
            ERROR("received int data is larger then packet ep %02X\n", ep);
            len -= (sum - p->iov.size);
            sum = p->iov.size;
            status = usb_redir_babble;
        }

        usb_packet_copy(p, intp->data, len);

        intp_to_free = intp;
        if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
            sum >= p->iov.size)
            break;
    }
    if (intp_to_free) {
        bufp_free(dev, intp_to_free, ep);
    }
    DPRINTF("interrupt-token-in ep %02X summary status %d len %d\n", ep,
            status, sum);
    usbredir_handle_status(dev, p, status);
}
static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
                                              USBPacket *p, uint8_t ep)
{
     
    struct buf_packet *intp, *intp_to_free;
    int status, len, sum;

    if (!dev->endpoint[EP2I(ep)].interrupt_started &&
            !dev->endpoint[EP2I(ep)].interrupt_error) {
        struct usb_redir_start_interrupt_receiving_header start_int = {
            .endpoint = ep,
        };
         
        usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
                                                      &start_int);
        usbredirparser_do_write(dev->parser);
        DPRINTF("interrupt recv started ep %02X\n", ep);
        dev->endpoint[EP2I(ep)].interrupt_started = 1;
         
        dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
        dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
    }

     
    sum = 0;
    QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
        sum += intp->len;
        if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
            sum >= p->iov.size)
            break;
    }

    if (intp == NULL) {
        DPRINTF2("interrupt-token-in ep %02X, no intp, buffered %d\n", ep, sum);
         
        status = dev->endpoint[EP2I(ep)].interrupt_error;
        dev->endpoint[EP2I(ep)].interrupt_error = 0;
        if (status) {
            usbredir_handle_status(dev, p, status);
        } else {
            p->status = USB_RET_NAK;
        }
        return;
    }

     
    sum = 0;
    status = usb_redir_success;
    intp_to_free = NULL;
    QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
        if (intp_to_free) {
            bufp_free(dev, intp_to_free, ep);
        }
        DPRINTF("interrupt-token-in ep %02X fragment status %d len %d\n", ep,
                intp->status, intp->len);

        sum += intp->len;
        len = intp->len;
        if (status == usb_redir_success) {
            status = intp->status;
        }
        if (sum > p->iov.size) {
            ERROR("received int data is larger then packet ep %02X\n", ep);
            len -= (sum - p->iov.size);
            sum = p->iov.size;
            status = usb_redir_babble;
        }

        usb_packet_copy(p, intp->data, len);

        intp_to_free = intp;
        if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
            sum >= p->iov.size)
            break;
    }
    if (intp_to_free) {
        bufp_free(dev, intp_to_free, ep);
    }
    DPRINTF("interrupt-token-in ep %02X summary status %d len %d\n", ep,
            status, sum);
    usbredir_handle_status(dev, p, status);
}