Commit ce5e5b52 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'kraxel/usb.70' into staging



* kraxel/usb.70:
  ehci: fix migration
  xhci: Fix some DMA host endian bugs
  usb/combined-packet: Move freeing of combined to usb_combined_packet_remove()
  xhci: Add support for packets with both data and an error status
  ehci: Add support for packets with both data and an error status
  ehci: Get rid of the magical PROC_ERR status
  usb-redir: Allow packets to have both data and an error-status
  usb: split packet result into actual_length + status

Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parents bf0dfb69 9d153047
Loading
Loading
Loading
Loading
+14 −10
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#define USB_TOKEN_IN    0x69 /* device -> host */
#define USB_TOKEN_OUT   0xe1 /* host -> device */

#define USB_RET_SUCCESS           (0)
#define USB_RET_NODEV             (-1)
#define USB_RET_NAK               (-2)
#define USB_RET_STALL             (-3)
@@ -280,18 +281,20 @@ typedef struct USBDeviceClass {
     * Process control request.
     * Called from handle_packet().
     *
     * Returns length or one of the USB_RET_ codes.
     * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
     * then the number of bytes transfered is stored in p->actual_length
     */
    int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
    void (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
                           int index, int length, uint8_t *data);

    /*
     * Process data transfers (both BULK and ISOC).
     * Called from handle_packet().
     *
     * Returns length or one of the USB_RET_ codes.
     * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
     * then the number of bytes transfered is stored in p->actual_length
     */
    int (*handle_data)(USBDevice *dev, USBPacket *p);
    void (*handle_data)(USBDevice *dev, USBPacket *p);

    void (*set_interface)(USBDevice *dev, int interface,
                          int alt_old, int alt_new);
@@ -354,7 +357,8 @@ struct USBPacket {
    uint64_t parameter; /* control transfers */
    bool short_not_ok;
    bool int_req;
    int result; /* transfer length or USB_RET_* status code */
    int status; /* USB_RET_* status code */
    int actual_length; /* Number of bytes actually transfered */
    /* Internal use by the USB layer.  */
    USBPacketState state;
    USBCombinedPacket *combined;
@@ -388,7 +392,7 @@ static inline bool usb_packet_is_inflight(USBPacket *p)

USBDevice *usb_find_device(USBPort *port, uint8_t addr);

int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_packet_complete_one(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
@@ -523,10 +527,10 @@ void usb_device_handle_attach(USBDevice *dev);

void usb_device_handle_reset(USBDevice *dev);

int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value,
                              int index, int length, uint8_t *data);
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
                               int val, int index, int length, uint8_t *data);

int usb_device_handle_data(USBDevice *dev, USBPacket *p);
void usb_device_handle_data(USBDevice *dev, USBPacket *p);

void usb_device_set_interface(USBDevice *dev, int interface,
                              int alt_old, int alt_new);
+5 −8
Original line number Diff line number Diff line
@@ -140,24 +140,21 @@ void usb_device_handle_reset(USBDevice *dev)
    }
}

int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
                               int value, int index, int length, uint8_t *data)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_control) {
        return klass->handle_control(dev, p, request, value, index, length,
                                         data);
        klass->handle_control(dev, p, request, value, index, length, data);
    }
    return -ENOSYS;
}

int usb_device_handle_data(USBDevice *dev, USBPacket *p)
void usb_device_handle_data(USBDevice *dev, USBPacket *p)
{
    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
    if (klass->handle_data) {
        return klass->handle_data(dev, p);
        klass->handle_data(dev, p);
    }
    return -ENOSYS;
}

const char *usb_device_get_product_desc(USBDevice *dev)
+31 −27
Original line number Diff line number Diff line
@@ -31,12 +31,16 @@ static void usb_combined_packet_add(USBCombinedPacket *combined, USBPacket *p)
    p->combined = combined;
}

/* Note will free combined when the last packet gets removed */
static void usb_combined_packet_remove(USBCombinedPacket *combined,
                                       USBPacket *p)
{
    assert(p->combined == combined);
    p->combined = NULL;
    QTAILQ_REMOVE(&combined->packets, p, combined_entry);
    if (QTAILQ_EMPTY(&combined->packets)) {
        g_free(combined);
    }
}

/* Also handles completion of non combined packets for pipelined input eps */
@@ -45,9 +49,8 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
    USBCombinedPacket *combined = p->combined;
    USBEndpoint *ep = p->ep;
    USBPacket *next;
    enum { completing, complete, leftover };
    int result, state = completing;
    bool short_not_ok;
    int status, actual_length;
    bool short_not_ok, done = false;

    if (combined == NULL) {
        usb_packet_complete_one(dev, p);
@@ -56,37 +59,39 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)

    assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets));

    result = combined->first->result;
    status = combined->first->status;
    actual_length = combined->first->actual_length;
    short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok;

    QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) {
        if (state == completing) {
        if (!done) {
            /* Distribute data over uncombined packets */
            if (result >= p->iov.size) {
                p->result = p->iov.size;
            if (actual_length >= p->iov.size) {
                p->actual_length = p->iov.size;
            } else {
                /* Send short or error packet to complete the transfer */
                p->result = result;
                state = complete;
                p->actual_length = actual_length;
                done = true;
            }
            /* Report status on the last packet */
            if (done || next == NULL) {
                p->status = status;
            } else {
                p->status = USB_RET_SUCCESS;
            }
            p->short_not_ok = short_not_ok;
            /* Note will free combined when the last packet gets removed! */
            usb_combined_packet_remove(combined, p);
            usb_packet_complete_one(dev, p);
            result -= p->result;
            actual_length -= p->actual_length;
        } else {
            /* Remove any leftover packets from the queue */
            state = leftover;
            p->result = USB_RET_REMOVE_FROM_QUEUE;
            p->status = USB_RET_REMOVE_FROM_QUEUE;
            /* Note will free combined on the last packet! */
            dev->port->ops->complete(dev->port, p);
        }
    }
    /*
     * If we had leftover packets the hcd driver will have cancelled them
     * and usb_combined_packet_cancel has already freed combined!
     */
    if (state != leftover) {
        g_free(combined);
    }
    /* Do not use combined here, it has been freed! */
leave:
    /* Check if there are packets in the queue waiting for our completion */
    usb_ep_combine_input_packets(ep);
@@ -97,14 +102,13 @@ void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p)
{
    USBCombinedPacket *combined = p->combined;
    assert(combined != NULL);
    USBPacket *first = p->combined->first;

    /* Note will free combined on the last packet! */
    usb_combined_packet_remove(combined, p);
    if (p == combined->first) {
    if (p == first) {
        usb_device_cancel_packet(dev, p);
    }
    if (QTAILQ_EMPTY(&combined->packets)) {
        g_free(combined);
    }
}

/*
@@ -117,7 +121,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
{
    USBPacket *p, *u, *next, *prev = NULL, *first = NULL;
    USBPort *port = ep->dev->port;
    int ret, totalsize;
    int totalsize;

    assert(ep->pipeline);
    assert(ep->pid == USB_TOKEN_IN);
@@ -125,7 +129,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
    QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) {
        /* Empty the queue on a halt */
        if (ep->halted) {
            p->result = USB_RET_REMOVE_FROM_QUEUE;
            p->status = USB_RET_REMOVE_FROM_QUEUE;
            port->ops->complete(port, p);
            continue;
        }
@@ -166,8 +170,8 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
                next == NULL ||
                /* Work around for Linux usbfs bulk splitting + migration */
                (totalsize == 16348 && p->int_req)) {
            ret = usb_device_handle_data(ep->dev, first);
            assert(ret == USB_RET_ASYNC);
            usb_device_handle_data(ep->dev, first);
            assert(first->status == USB_RET_ASYNC);
            if (first->combined) {
                QTAILQ_FOREACH(u, &first->combined->packets, combined_entry) {
                    usb_packet_set_state(u, USB_PACKET_ASYNC);
+109 −100
Original line number Diff line number Diff line
@@ -97,17 +97,17 @@ void usb_wakeup(USBEndpoint *ep)
#define SETUP_STATE_ACK   3
#define SETUP_STATE_PARAM 4

static int do_token_setup(USBDevice *s, USBPacket *p)
static void do_token_setup(USBDevice *s, USBPacket *p)
{
    int request, value, index;
    int ret = 0;

    if (p->iov.size != 8) {
        return USB_RET_STALL;
        p->status = USB_RET_STALL;
        return;
    }

    usb_packet_copy(p, s->setup_buf, p->iov.size);
    p->result = 0;
    p->actual_length = 0;
    s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
    s->setup_index = 0;

@@ -116,24 +116,26 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
    index   = (s->setup_buf[5] << 8) | s->setup_buf[4];

    if (s->setup_buf[0] & USB_DIR_IN) {
        ret = usb_device_handle_control(s, p, request, value, index,
        usb_device_handle_control(s, p, request, value, index,
                                  s->setup_len, s->data_buf);
        if (ret == USB_RET_ASYNC) {
        if (p->status == USB_RET_ASYNC) {
            s->setup_state = SETUP_STATE_SETUP;
             return USB_RET_ASYNC;
        }
        if (ret < 0)
            return ret;
        if (p->status != USB_RET_SUCCESS) {
            return;
        }

        if (ret < s->setup_len)
            s->setup_len = ret;
        if (p->actual_length < s->setup_len) {
            s->setup_len = p->actual_length;
        }
        s->setup_state = SETUP_STATE_DATA;
    } else {
        if (s->setup_len > sizeof(s->data_buf)) {
            fprintf(stderr,
                "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
                s->setup_len, sizeof(s->data_buf));
            return USB_RET_STALL;
            p->status = USB_RET_STALL;
            return;
        }
        if (s->setup_len == 0)
            s->setup_state = SETUP_STATE_ACK;
@@ -141,13 +143,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
            s->setup_state = SETUP_STATE_DATA;
    }

    return ret;
    p->actual_length = 8;
}

static int do_token_in(USBDevice *s, USBPacket *p)
static void do_token_in(USBDevice *s, USBPacket *p)
{
    int request, value, index;
    int ret = 0;

    assert(p->ep->nr == 0);

@@ -158,19 +159,15 @@ static int do_token_in(USBDevice *s, USBPacket *p)
    switch(s->setup_state) {
    case SETUP_STATE_ACK:
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
            ret = usb_device_handle_control(s, p, request, value, index,
            usb_device_handle_control(s, p, request, value, index,
                                      s->setup_len, s->data_buf);
            if (ret == USB_RET_ASYNC) {
                return USB_RET_ASYNC;
            if (p->status == USB_RET_ASYNC) {
                return;
            }
            s->setup_state = SETUP_STATE_IDLE;
            if (ret > 0)
                return 0;
            return ret;
            p->actual_length = 0;
        }

        /* return 0 byte */
        return 0;
        break;

    case SETUP_STATE_DATA:
        if (s->setup_buf[0] & USB_DIR_IN) {
@@ -180,20 +177,21 @@ static int do_token_in(USBDevice *s, USBPacket *p)
            }
            usb_packet_copy(p, s->data_buf + s->setup_index, len);
            s->setup_index += len;
            if (s->setup_index >= s->setup_len)
            if (s->setup_index >= s->setup_len) {
                s->setup_state = SETUP_STATE_ACK;
            return len;
            }

            return;
        }
        s->setup_state = SETUP_STATE_IDLE;
        return USB_RET_STALL;
        p->status = USB_RET_STALL;
        break;

    default:
        return USB_RET_STALL;
        p->status = USB_RET_STALL;
    }
}

static int do_token_out(USBDevice *s, USBPacket *p)
static void do_token_out(USBDevice *s, USBPacket *p)
{
    assert(p->ep->nr == 0);

@@ -205,7 +203,7 @@ static int do_token_out(USBDevice *s, USBPacket *p)
        } else {
            /* ignore additional output */
        }
        return 0;
        break;

    case SETUP_STATE_DATA:
        if (!(s->setup_buf[0] & USB_DIR_IN)) {
@@ -215,23 +213,23 @@ static int do_token_out(USBDevice *s, USBPacket *p)
            }
            usb_packet_copy(p, s->data_buf + s->setup_index, len);
            s->setup_index += len;
            if (s->setup_index >= s->setup_len)
            if (s->setup_index >= s->setup_len) {
                s->setup_state = SETUP_STATE_ACK;
            return len;
            }

            return;
        }
        s->setup_state = SETUP_STATE_IDLE;
        return USB_RET_STALL;
        p->status = USB_RET_STALL;
        break;

    default:
        return USB_RET_STALL;
        p->status = USB_RET_STALL;
    }
}

static int do_parameter(USBDevice *s, USBPacket *p)
static void do_parameter(USBDevice *s, USBPacket *p)
{
    int request, value, index;
    int i, ret = 0;
    int i, request, value, index;

    for (i = 0; i < 8; i++) {
        s->setup_buf[i] = p->parameter >> (i*8);
@@ -249,27 +247,27 @@ static int do_parameter(USBDevice *s, USBPacket *p)
        fprintf(stderr,
                "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
                s->setup_len, sizeof(s->data_buf));
        return USB_RET_STALL;
        p->status = USB_RET_STALL;
        return;
    }

    if (p->pid == USB_TOKEN_OUT) {
        usb_packet_copy(p, s->data_buf, s->setup_len);
    }

    ret = usb_device_handle_control(s, p, request, value, index,
    usb_device_handle_control(s, p, request, value, index,
                              s->setup_len, s->data_buf);
    if (ret < 0) {
        return ret;
    if (p->status == USB_RET_ASYNC) {
        return;
    }

    if (ret < s->setup_len) {
        s->setup_len = ret;
    if (p->actual_length < s->setup_len) {
        s->setup_len = p->actual_length;
    }
    if (p->pid == USB_TOKEN_IN) {
        p->actual_length = 0;
        usb_packet_copy(p, s->data_buf, s->setup_len);
    }

    return ret;
}

/* ctrl complete function for devices which use usb_generic_handle_packet and
@@ -278,30 +276,30 @@ static int do_parameter(USBDevice *s, USBPacket *p)
   usb_packet_complete to complete their async control packets. */
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
{
    if (p->result < 0) {
    if (p->status < 0) {
        s->setup_state = SETUP_STATE_IDLE;
    }

    switch (s->setup_state) {
    case SETUP_STATE_SETUP:
        if (p->result < s->setup_len) {
            s->setup_len = p->result;
        if (p->actual_length < s->setup_len) {
            s->setup_len = p->actual_length;
        }
        s->setup_state = SETUP_STATE_DATA;
        p->result = 8;
        p->actual_length = 8;
        break;

    case SETUP_STATE_ACK:
        s->setup_state = SETUP_STATE_IDLE;
        p->result = 0;
        p->actual_length = 0;
        break;

    case SETUP_STATE_PARAM:
        if (p->result < s->setup_len) {
            s->setup_len = p->result;
        if (p->actual_length < s->setup_len) {
            s->setup_len = p->actual_length;
        }
        if (p->pid == USB_TOKEN_IN) {
            p->result = 0;
            p->actual_length = 0;
            usb_packet_copy(p, s->data_buf, s->setup_len);
        }
        break;
@@ -342,40 +340,57 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr)
    return usb_device_find_device(dev, addr);
}

static int usb_process_one(USBPacket *p)
static void usb_process_one(USBPacket *p)
{
    USBDevice *dev = p->ep->dev;

    /*
     * Handlers expect status to be initialized to USB_RET_SUCCESS, but it
     * can be USB_RET_NAK here from a previous usb_process_one() call,
     * or USB_RET_ASYNC from going through usb_queue_one().
     */
    p->status = USB_RET_SUCCESS;

    if (p->ep->nr == 0) {
        /* control pipe */
        if (p->parameter) {
            return do_parameter(dev, p);
            do_parameter(dev, p);
            return;
        }
        switch (p->pid) {
        case USB_TOKEN_SETUP:
            return do_token_setup(dev, p);
            do_token_setup(dev, p);
            break;
        case USB_TOKEN_IN:
            return do_token_in(dev, p);
            do_token_in(dev, p);
            break;
        case USB_TOKEN_OUT:
            return do_token_out(dev, p);
            do_token_out(dev, p);
            break;
        default:
            return USB_RET_STALL;
            p->status = USB_RET_STALL;
        }
    } else {
        /* data pipe */
        return usb_device_handle_data(dev, p);
        usb_device_handle_data(dev, p);
    }
}

/* Hand over a packet to a device for processing.  Return value
static void usb_queue_one(USBPacket *p)
{
    usb_packet_set_state(p, USB_PACKET_QUEUED);
    QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
    p->status = USB_RET_ASYNC;
}

/* Hand over a packet to a device for processing.  p->status ==
   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)
void usb_handle_packet(USBDevice *dev, USBPacket *p)
{
    int ret;

    if (dev == NULL) {
        return USB_RET_NODEV;
        p->status = USB_RET_NODEV;
        return;
    }
    assert(dev == p->ep->dev);
    assert(dev->state == USB_STATE_DEFAULT);
@@ -389,32 +404,26 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
    }

    if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
        ret = usb_process_one(p);
        if (ret == USB_RET_ASYNC) {
        usb_process_one(p);
        if (p->status == 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 if (p->status == USB_RET_ADD_TO_QUEUE) {
            usb_queue_one(p);
        } 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;
            if (p->status != USB_RET_NAK) {
                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);
        usb_queue_one(p);
    }
    return ret;
}

void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
@@ -422,9 +431,10 @@ 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);
    assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);

    if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) {
    if (p->status != USB_RET_SUCCESS ||
            (p->short_not_ok && (p->actual_length < p->iov.size))) {
        ep->halted = true;
    }
    usb_packet_set_state(p, USB_PACKET_COMPLETE);
@@ -438,7 +448,6 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
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);
@@ -447,7 +456,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
        p = QTAILQ_FIRST(&ep->queue);
        if (ep->halted) {
            /* Empty the queue on a halt */
            p->result = USB_RET_REMOVE_FROM_QUEUE;
            p->status = USB_RET_REMOVE_FROM_QUEUE;
            dev->port->ops->complete(dev->port, p);
            continue;
        }
@@ -455,12 +464,11 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
            break;
        }
        usb_packet_check_state(p, USB_PACKET_QUEUED);
        ret = usb_process_one(p);
        if (ret == USB_RET_ASYNC) {
        usb_process_one(p);
        if (p->status == USB_RET_ASYNC) {
            usb_packet_set_state(p, USB_PACKET_ASYNC);
            break;
        }
        p->result = ret;
        usb_packet_complete_one(ep->dev, p);
    }
}
@@ -541,7 +549,8 @@ void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
    p->id = id;
    p->pid = pid;
    p->ep = ep;
    p->result = 0;
    p->status = USB_RET_SUCCESS;
    p->actual_length = 0;
    p->parameter = 0;
    p->short_not_ok = short_not_ok;
    p->int_req = int_req;
@@ -557,31 +566,31 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)

void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
{
    assert(p->result >= 0);
    assert(p->result + bytes <= p->iov.size);
    assert(p->actual_length >= 0);
    assert(p->actual_length + bytes <= p->iov.size);
    switch (p->pid) {
    case USB_TOKEN_SETUP:
    case USB_TOKEN_OUT:
        iov_to_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
        iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
        break;
    case USB_TOKEN_IN:
        iov_from_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
        iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
        break;
    default:
        fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
        abort();
    }
    p->result += bytes;
    p->actual_length += bytes;
}

void usb_packet_skip(USBPacket *p, size_t bytes)
{
    assert(p->result >= 0);
    assert(p->result + bytes <= p->iov.size);
    assert(p->actual_length >= 0);
    assert(p->actual_length + bytes <= p->iov.size);
    if (p->pid == USB_TOKEN_IN) {
        iov_memset(p->iov.iov, p->iov.niov, p->result, 0, bytes);
        iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes);
    }
    p->result += bytes;
    p->actual_length += bytes;
}

void usb_packet_cleanup(USBPacket *p)
+11 −5
Original line number Diff line number Diff line
@@ -626,7 +626,8 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
    return pos;
}

int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
                            int value, uint8_t *dest, size_t len)
{
    const USBDesc *desc = usb_device_get_usb_desc(dev);
    const USBDescDevice *other_dev;
@@ -696,6 +697,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
            ret = len;
        }
        memcpy(dest, buf, ret);
        p->actual_length = ret;
        ret = 0;
    }
    return ret;
}
@@ -715,7 +718,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
        break;

    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
        ret = usb_desc_get_descriptor(dev, value, data, length);
        ret = usb_desc_get_descriptor(dev, p, value, data, length);
        break;

    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
@@ -724,7 +727,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         * the non zero value of bConfigurationValue.
         */
        data[0] = dev->config ? dev->config->bConfigurationValue : 0;
        ret = 1;
        p->actual_length = 1;
        ret = 0;
        break;
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
        ret = usb_desc_set_config(dev, value);
@@ -749,7 +753,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
            data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
        }
        data[1] = 0x00;
        ret = 2;
        p->actual_length = 2;
        ret = 0;
        break;
    }
    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
@@ -772,7 +777,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
            break;
        }
        data[0] = dev->altsetting[index];
        ret = 1;
        p->actual_length = 1;
        ret = 0;
        break;
    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
        ret = usb_desc_set_interface(dev, index, value);
Loading