Example #1
0
/* Hand over a packet to a device for processing.  Return value
   USB_RET_ASYNC indicates the processing isn't finished yet, the
   driver will call usb_packet_complete() when done processing it. */
int usb_handle_packet(USBDevice *dev, USBPacket *p)
{
    int ret;

    if (dev == NULL) {
        return USB_RET_NODEV;
    }
    assert(dev == p->ep->dev);
    assert(dev->state == USB_STATE_DEFAULT);
    usb_packet_check_state(p, USB_PACKET_SETUP);
    assert(p->ep != NULL);

    if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
        ret = usb_process_one(p);
        if (ret == USB_RET_ASYNC) {
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
        } else {
            p->result = ret;
            usb_packet_set_state(p, USB_PACKET_COMPLETE);
        }
    } else {
        ret = USB_RET_ASYNC;
        usb_packet_set_state(p, USB_PACKET_QUEUED);
        QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
    }
    return ret;
}
Example #2
0
/* Notify the controller that an async packet is complete.  This should only
   be called for packets previously deferred by returning USB_RET_ASYNC from
   handle_packet. */
void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
    USBEndpoint *ep = p->ep;
    int ret;

    usb_packet_check_state(p, USB_PACKET_ASYNC);
    assert(QTAILQ_FIRST(&ep->queue) == p);
    usb_packet_set_state(p, USB_PACKET_COMPLETE);
    QTAILQ_REMOVE(&ep->queue, p, queue);
    dev->port->ops->complete(dev->port, p);

    while (!QTAILQ_EMPTY(&ep->queue)) {
        p = QTAILQ_FIRST(&ep->queue);
        if (p->state == USB_PACKET_ASYNC) {
            break;
        }
        usb_packet_check_state(p, USB_PACKET_QUEUED);
        ret = usb_process_one(p);
        if (ret == USB_RET_ASYNC) {
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            break;
        }
        p->result = ret;
        usb_packet_set_state(p, USB_PACKET_COMPLETE);
        QTAILQ_REMOVE(&ep->queue, p, queue);
        dev->port->ops->complete(dev->port, p);
    }
}
Example #3
0
File: core.c Project: gbraad/qemu
/* Notify the controller that an async packet is complete.  This should only
   be called for packets previously deferred by returning USB_RET_ASYNC from
   handle_packet. */
void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
    USBEndpoint *ep = p->ep;
    int ret;

    usb_packet_check_state(p, USB_PACKET_ASYNC);
    usb_packet_complete_one(dev, p);

    while (!QTAILQ_EMPTY(&ep->queue)) {
        p = QTAILQ_FIRST(&ep->queue);
        if (ep->halted) {
            /* Empty the queue on a halt */
            p->result = USB_RET_REMOVE_FROM_QUEUE;
            dev->port->ops->complete(dev->port, p);
            continue;
        }
        if (p->state == USB_PACKET_ASYNC) {
            break;
        }
        usb_packet_check_state(p, USB_PACKET_QUEUED);
        ret = usb_process_one(p);
        if (ret == USB_RET_ASYNC) {
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            break;
        }
        p->result = ret;
        usb_packet_complete_one(ep->dev, p);
    }
}
Example #4
0
File: core.c Project: gbraad/qemu
/* Hand over a packet to a device for processing.  Return value
   USB_RET_ASYNC indicates the processing isn't finished yet, the
   driver will call usb_packet_complete() when done processing it. */
int usb_handle_packet(USBDevice *dev, USBPacket *p)
{
    int ret;

    if (dev == NULL) {
        return USB_RET_NODEV;
    }
    assert(dev == p->ep->dev);
    assert(dev->state == USB_STATE_DEFAULT);
    usb_packet_check_state(p, USB_PACKET_SETUP);
    assert(p->ep != NULL);

    /* Submitting a new packet clears halt */
    if (p->ep->halted) {
        assert(QTAILQ_EMPTY(&p->ep->queue));
        p->ep->halted = false;
    }

    if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
        ret = usb_process_one(p);
        if (ret == USB_RET_ASYNC) {
            assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
        } else if (ret == USB_RET_ADD_TO_QUEUE) {
            usb_packet_set_state(p, USB_PACKET_QUEUED);
            QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
            ret = USB_RET_ASYNC;
        } else {
            /*
             * When pipelining is enabled usb-devices must always return async,
             * otherwise packets can complete out of order!
             */
            assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
            if (ret != USB_RET_NAK) {
                p->result = ret;
                usb_packet_set_state(p, USB_PACKET_COMPLETE);
            }
        }
    } else {
        ret = USB_RET_ASYNC;
        usb_packet_set_state(p, USB_PACKET_QUEUED);
        QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
    }
    return ret;
}
Example #5
0
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep)
{
    assert(!usb_packet_is_inflight(p));
    p->pid = pid;
    p->ep = ep;
    p->result = 0;
    qemu_iovec_reset(&p->iov);
    usb_packet_set_state(p, USB_PACKET_SETUP);
}
Example #6
0
/* Cancel an active packet.  The packed must have been deferred by
   returning USB_RET_ASYNC from handle_packet, and not yet
   completed.  */
void usb_cancel_packet(USBPacket * p)
{
    bool callback = (p->state == USB_PACKET_ASYNC);
    assert(usb_packet_is_inflight(p));
    usb_packet_set_state(p, USB_PACKET_CANCELED);
    QTAILQ_REMOVE(&p->ep->queue, p, queue);
    if (callback) {
        usb_device_cancel_packet(p->ep->dev, p);
    }
}
Example #7
0
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id)
{
    assert(!usb_packet_is_inflight(p));
    assert(p->iov.iov != NULL);
    p->id = id;
    p->pid = pid;
    p->ep = ep;
    p->result = 0;
    p->parameter = 0;
    qemu_iovec_reset(&p->iov);
    usb_packet_set_state(p, USB_PACKET_SETUP);
}
Example #8
0
static void __usb_packet_complete(USBDevice *dev, USBPacket *p)
{
    USBEndpoint *ep = p->ep;

    assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);

    if (p->result < 0) {
        ep->halted = true;
    }
    usb_packet_set_state(p, USB_PACKET_COMPLETE);
    QTAILQ_REMOVE(&ep->queue, p, queue);
    dev->port->ops->complete(dev->port, p);
}
Example #9
0
File: core.c Project: gbraad/qemu
void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
{
    USBEndpoint *ep = p->ep;

    assert(QTAILQ_FIRST(&ep->queue) == p);
    assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);

    if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) {
        ep->halted = true;
    }
    usb_packet_set_state(p, USB_PACKET_COMPLETE);
    QTAILQ_REMOVE(&ep->queue, p, queue);
    dev->port->ops->complete(dev->port, p);
}
Example #10
0
File: core.c Project: gbraad/qemu
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
                      bool short_not_ok, bool int_req)
{
    assert(!usb_packet_is_inflight(p));
    assert(p->iov.iov != NULL);
    p->id = id;
    p->pid = pid;
    p->ep = ep;
    p->result = 0;
    p->parameter = 0;
    p->short_not_ok = short_not_ok;
    p->int_req = int_req;
    p->combined = NULL;
    qemu_iovec_reset(&p->iov);
    usb_packet_set_state(p, USB_PACKET_SETUP);
}
Example #11
0
/* Notify the controller that an async packet is complete.  This should only
   be called for packets previously deferred by returning USB_RET_ASYNC from
   handle_packet. */
void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
    USBEndpoint *ep = p->ep;
    int ret;

    usb_packet_check_state(p, USB_PACKET_ASYNC);
    assert(QTAILQ_FIRST(&ep->queue) == p);
    __usb_packet_complete(dev, p);

    while (!ep->halted && !QTAILQ_EMPTY(&ep->queue)) {
        p = QTAILQ_FIRST(&ep->queue);
        if (p->state == USB_PACKET_ASYNC) {
            break;
        }
        usb_packet_check_state(p, USB_PACKET_QUEUED);
        ret = usb_process_one(p);
        if (ret == USB_RET_ASYNC) {
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            break;
        }
        p->result = ret;
        __usb_packet_complete(ep->dev, p);
    }
}