static void async_complete(void *opaque)

{

    USBHostDevice *s = opaque;

    AsyncURB *aurb;

    int urbs = 0;



    while (1) {

        USBPacket *p;



        int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);

        if (r < 0) {

            if (errno == EAGAIN) {

                if (urbs > 2) {

                    fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);

                }

                return;

            }

            if (errno == ENODEV) {

                if (!s->closing) {

                    trace_usb_host_disconnect(s->bus_num, s->addr);

                    do_disconnect(s);

                }

                return;

            }



            perror("USBDEVFS_REAPURBNDELAY");

            return;

        }



        DPRINTF("husb: async completed. aurb %p status %d alen %d\n",

                aurb, aurb->urb.status, aurb->urb.actual_length);



        



        if (aurb->iso_frame_idx == -1) {

            int inflight;

            int pid = (aurb->urb.endpoint & USB_DIR_IN) ?

                USB_TOKEN_IN : USB_TOKEN_OUT;

            int ep = aurb->urb.endpoint & 0xf;

            if (aurb->urb.status == -EPIPE) {

                set_halt(s, pid, ep);

            }

            aurb->iso_frame_idx = 0;

            urbs++;

            inflight = change_iso_inflight(s, pid, ep, -1);

            if (inflight == 0 && is_iso_started(s, pid, ep)) {

                fprintf(stderr, "husb: out of buffers for iso stream\n");

            }

            continue;

        }



        p = aurb->packet;

        trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,

                                    aurb->urb.actual_length, aurb->more);



        if (p) {

            switch (aurb->urb.status) {

            case 0:

                p->result += aurb->urb.actual_length;

                break;



            case -EPIPE:

                set_halt(s, p->pid, p->devep);

                p->result = USB_RET_STALL;

                break;



            default:

                p->result = USB_RET_NAK;

                break;

            }



            if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {

                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);

                usb_generic_async_ctrl_complete(&s->dev, p);

            } else if (!aurb->more) {

                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);

                usb_packet_complete(&s->dev, p);

            }

        }



        async_free(aurb);

    }

}
