Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-7' into st…
Browse files Browse the repository at this point in the history
…aging

usb: usb3 streams support for usb-host and usb-redir
usb: xhci and mtp bugfixes.

# gpg: Signature made Mon 26 May 2014 09:44:09 BST using RSA key ID D3E87138
# gpg: Can't check signature: public key not found

* remotes/kraxel/tags/pull-usb-7:
  usb-host-libusb: Set stream id when submitting bulk-stream transfers
  usb-host-libusb: Add alloc / free streams ops
  usb-host-libusb: Fill in endpoint max_streams when available
  usb-redir: Add support for bulk streams
  usb-mtp: handle usb_mtp_get_object failure
  usb-mtp: handle lseek failure
  usb-mtp: use bool to track MTPObject init status
  xhci: add xhci_get_flag
  xhci: add endpoint cap on express bus only
  xhci: child detach fix

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed May 28, 2014
2 parents 53651ec + 8d1bd3c commit 972b09c
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 23 deletions.
28 changes: 19 additions & 9 deletions hw/usb/dev-mtp.c
Expand Up @@ -46,6 +46,7 @@ enum mtp_code {

/* response codes */
RES_OK = 0x2001,
RES_GENERAL_ERROR = 0x2002,
RES_SESSION_NOT_OPEN = 0x2003,
RES_INVALID_TRANSACTION_ID = 0x2004,
RES_OPERATION_NOT_SUPPORTED = 0x2005,
Expand Down Expand Up @@ -109,7 +110,8 @@ struct MTPObject {
struct stat stat;
MTPObject *parent;
MTPObject **children;
int32_t nchildren;
uint32_t nchildren;
bool have_children;
QTAILQ_ENTRY(MTPObject) next;
};

Expand Down Expand Up @@ -273,7 +275,6 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
o->handle = handle;
o->parent = parent;
o->name = g_strdup(name);
o->nchildren = -1;
if (parent == NULL) {
o->path = g_strdup(name);
} else {
Expand Down Expand Up @@ -340,7 +341,11 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
struct dirent *entry;
DIR *dir;

o->nchildren = 0;
if (o->have_children) {
return;
}
o->have_children = true;

dir = opendir(o->path);
if (!dir) {
return;
Expand Down Expand Up @@ -698,7 +703,10 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
if (offset > o->stat.st_size) {
offset = o->stat.st_size;
}
lseek(d->fd, offset, SEEK_SET);
if (lseek(d->fd, offset, SEEK_SET) < 0) {
usb_mtp_data_free(d);
return NULL;
}

d->length = c->argv[2];
if (d->length > o->stat.st_size - offset) {
Expand Down Expand Up @@ -789,9 +797,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
c->trans, 0, 0, 0);
return;
}
if (o->nchildren == -1) {
usb_mtp_object_readdir(s, o);
}
usb_mtp_object_readdir(s, o);
if (c->code == CMD_GET_NUM_OBJECTS) {
trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
nres = 1;
Expand Down Expand Up @@ -823,7 +829,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
}
data_in = usb_mtp_get_object(s, c, o);
if (NULL == data_in) {
fprintf(stderr, "%s: TODO: handle error\n", __func__);
usb_mtp_queue_result(s, RES_GENERAL_ERROR,
c->trans, 0, 0, 0);
return;
}
break;
case CMD_GET_PARTIAL_OBJECT:
Expand All @@ -840,7 +848,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
}
data_in = usb_mtp_get_partial_object(s, c, o);
if (NULL == data_in) {
fprintf(stderr, "%s: TODO: handle error\n", __func__);
usb_mtp_queue_result(s, RES_GENERAL_ERROR,
c->trans, 0, 0, 0);
return;
}
nres = 1;
res0 = data_in->length;
Expand Down
17 changes: 12 additions & 5 deletions hw/usb/hcd-xhci.c
Expand Up @@ -621,6 +621,11 @@ static const char *ep_state_name(uint32_t state)
ARRAY_SIZE(ep_state_names));
}

static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit)
{
return xhci->flags & (1 << bit);
}

static uint64_t xhci_mfindex_get(XHCIState *xhci)
{
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
Expand Down Expand Up @@ -3435,7 +3440,7 @@ static void xhci_child_detach(USBPort *uport, USBDevice *child)
USBBus *bus = usb_bus_from_device(child);
XHCIState *xhci = container_of(bus, XHCIState, bus);

xhci_detach_slot(xhci, uport);
xhci_detach_slot(xhci, child->port);
}

static USBPortOps xhci_uport_ops = {
Expand Down Expand Up @@ -3594,13 +3599,15 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
&xhci->mem);

ret = pcie_endpoint_cap_init(dev, 0xa0);
assert(ret >= 0);
if (pci_bus_is_express(dev->bus)) {
ret = pcie_endpoint_cap_init(dev, 0xa0);
assert(ret >= 0);
}

if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) {
msi_init(dev, 0x70, xhci->numintrs, true, false);
}
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) {
if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) {
msix_init(dev, xhci->numintrs,
&xhci->mem, 0, OFF_MSIX_TABLE,
&xhci->mem, 0, OFF_MSIX_PBA,
Expand Down
83 changes: 79 additions & 4 deletions hw/usb/host-libusb.c
Expand Up @@ -720,6 +720,9 @@ static void usb_host_ep_update(USBHostDevice *s)
struct libusb_config_descriptor *conf;
const struct libusb_interface_descriptor *intf;
const struct libusb_endpoint_descriptor *endp;
#if LIBUSBX_API_VERSION >= 0x01000103
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
#endif
uint8_t devep, type;
int pid, ep;
int rc, i, e;
Expand Down Expand Up @@ -765,6 +768,15 @@ static void usb_host_ep_update(USBHostDevice *s)
usb_ep_set_type(udev, pid, ep, type);
usb_ep_set_ifnum(udev, pid, ep, i);
usb_ep_set_halted(udev, pid, ep, 0);
#if LIBUSBX_API_VERSION >= 0x01000103
if (type == LIBUSB_TRANSFER_TYPE_BULK &&
libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
&endp_ss_comp) == LIBUSB_SUCCESS) {
usb_ep_set_max_streams(udev, pid, ep,
endp_ss_comp->bmAttributes);
libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp);
}
#endif
}
}

Expand Down Expand Up @@ -1202,10 +1214,23 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
usb_packet_copy(p, r->buffer, size);
}
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
r->buffer, size,
usb_host_req_complete_data, r,
BULK_TIMEOUT);
if (p->stream) {
#if LIBUSBX_API_VERSION >= 0x01000103
libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
r->buffer, size,
usb_host_req_complete_data, r,
BULK_TIMEOUT);
#else
usb_host_req_free(r);
p->status = USB_RET_STALL;
return;
#endif
} else {
libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
r->buffer, size,
usb_host_req_complete_data, r,
BULK_TIMEOUT);
}
break;
case USB_ENDPOINT_XFER_INT:
r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size);
Expand Down Expand Up @@ -1268,6 +1293,54 @@ static void usb_host_handle_reset(USBDevice *udev)
}
}

static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps, int streams)
{
#if LIBUSBX_API_VERSION >= 0x01000103
USBHostDevice *s = USB_HOST_DEVICE(udev);
unsigned char endpoints[30];
int i, rc;

for (i = 0; i < nr_eps; i++) {
endpoints[i] = eps[i]->nr;
if (eps[i]->pid == USB_TOKEN_IN) {
endpoints[i] |= 0x80;
}
}
rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps);
if (rc < 0) {
usb_host_libusb_error("libusb_alloc_streams", rc);
} else if (rc != streams) {
fprintf(stderr,
"libusb_alloc_streams: got less streams then requested %d < %d\n",
rc, streams);
}

return (rc == streams) ? 0 : -1;
#else
fprintf(stderr, "libusb_alloc_streams: error not implemented\n");
return -1;
#endif
}

static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps)
{
#if LIBUSBX_API_VERSION >= 0x01000103
USBHostDevice *s = USB_HOST_DEVICE(udev);
unsigned char endpoints[30];
int i;

for (i = 0; i < nr_eps; i++) {
endpoints[i] = eps[i]->nr;
if (eps[i]->pid == USB_TOKEN_IN) {
endpoints[i] |= 0x80;
}
}
libusb_free_streams(s->dh, endpoints, nr_eps);
#endif
}

/*
* This is *NOT* about restoring state. We have absolutely no idea
* what state the host device is in at the moment and whenever it is
Expand Down Expand Up @@ -1349,6 +1422,8 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usb_host_handle_reset;
uc->handle_destroy = usb_host_handle_destroy;
uc->flush_ep_queue = usb_host_flush_ep_queue;
uc->alloc_streams = usb_host_alloc_streams;
uc->free_streams = usb_host_free_streams;
dc->vmsd = &vmstate_usb_host;
dc->props = usb_host_dev_properties;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
Expand Down

0 comments on commit 972b09c

Please sign in to comment.