Skip to content

Commit

Permalink
Merge remote-tracking branch 'kraxel/usb.79' into staging
Browse files Browse the repository at this point in the history
# By Gerd Hoffmann (7) and Hans de Goede (3)
# Via Gerd Hoffmann
* kraxel/usb.79:
  usb-tablet: Don't claim wakeup capability for USB-2 version
  usb: update docs for bus name change
  usb-hub: report status changes only once
  usb-hub: limit chain length
  xhci: zap unused name field
  xhci: remove unimplemented printfs
  xhci: remove leftover debug printf
  xhci: fix numintrs sanity checks
  usb-redir: Add flow control support
  usb-redir: Fix crash on migration with no client connected
  • Loading branch information
Anthony Liguori committed Apr 8, 2013
2 parents 9196dd4 + aa1c9e9 commit 2a7a239
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 29 deletions.
20 changes: 10 additions & 10 deletions docs/usb2.txt
Expand Up @@ -11,7 +11,7 @@ one USB 2.0 bus driven by the EHCI controller. Devices must be
attached to the correct controller manually.

The '-usb' switch will make qemu create the UHCI controller as part of
the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0".
the PIIX3 chipset. The USB 1.1 bus will carry the name "usb-bus.0".

You can use the standard -device switch to add a EHCI controller to
your virtual machine. It is strongly recommended to specify an ID for
Expand All @@ -27,7 +27,7 @@ a complete example:
-drive if=none,id=usbstick,file=/path/to/image \
-usb \
-device usb-ehci,id=ehci \
-device usb-tablet,bus=usb.0 \
-device usb-tablet,bus=usb-bus.0 \
-device usb-storage,bus=ehci.0,drive=usbstick

This attaches a usb tablet to the UHCI adapter and a usb mass storage
Expand Down Expand Up @@ -88,22 +88,22 @@ ports (1-4), the emulated (1.1) USB hub has eight ports.

Plugging a tablet into UHCI port 1 works like this:

-device usb-tablet,bus=usb.0,port=1
-device usb-tablet,bus=usb-bus.0,port=1

Plugging a hub into UHCI port 2 works like this:

-device usb-hub,bus=usb.0,port=2
-device usb-hub,bus=usb-bus.0,port=2

Plugging a virtual usb stick into port 4 of the hub just plugged works
this way:

-device usb-storage,bus=usb.0,port=2.4,drive=...
-device usb-storage,bus=usb-bus.0,port=2.4,drive=...

You can do basically the same in the monitor using the device_add
command. If you want to unplug devices too you should specify some
unique id which you can use to refer to the device ...

(qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
(qemu) device_add usb-tablet,bus=usb-bus.0,port=1,id=my-tablet
(qemu) device_del my-tablet

... when unplugging it with device_del.
Expand Down Expand Up @@ -148,10 +148,10 @@ using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
for 1.1 devices. Passing through any device plugged into that port
and also assign them to the correct bus can be done this way:

qemu -M pc ${otheroptions} \
-usb \
-device usb-ehci,id=ehci \
-device usb-host,bus=usb.0,hostbus=3,hostport=1 \
qemu -M pc ${otheroptions} \
-usb \
-device usb-ehci,id=ehci \
-device usb-host,bus=usb-bus.0,hostbus=3,hostport=1 \
-device usb-host,bus=ehci.0,hostbus=1,hostport=1

enjoy,
Expand Down
1 change: 1 addition & 0 deletions hw/usb.h
Expand Up @@ -337,6 +337,7 @@ typedef struct USBPortOps {
struct USBPort {
USBDevice *dev;
int speedmask;
int hubcount;
char path[16];
USBPortOps *ops;
void *opaque;
Expand Down
2 changes: 2 additions & 0 deletions hw/usb/bus.c
Expand Up @@ -341,8 +341,10 @@ void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
if (upstream) {
snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
upstream->path, portnr);
downstream->hubcount = upstream->hubcount + 1;
} else {
snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
downstream->hubcount = 0;
}
}

Expand Down
2 changes: 1 addition & 1 deletion hw/usb/dev-hid.c
Expand Up @@ -236,7 +236,7 @@ static const USBDescDevice desc_device_tablet2 = {
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG_TABLET,
.bmAttributes = 0xa0,
.bmAttributes = 0x80,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface_tablet2,
Expand Down
12 changes: 11 additions & 1 deletion hw/usb/dev-hub.c
Expand Up @@ -25,13 +25,15 @@
#include "trace.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
#include "qemu/error-report.h"

#define NUM_PORTS 8

typedef struct USBHubPort {
USBPort port;
uint16_t wPortStatus;
uint16_t wPortChange;
uint16_t wPortChange_reported;
} USBHubPort;

typedef struct USBHubState {
Expand Down Expand Up @@ -466,8 +468,11 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
status = 0;
for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
if (port->wPortChange)
if (port->wPortChange &&
port->wPortChange_reported != port->wPortChange) {
status |= (1 << (i + 1));
}
port->wPortChange_reported = port->wPortChange;
}
if (status != 0) {
for(i = 0; i < n; i++) {
Expand Down Expand Up @@ -514,6 +519,11 @@ static int usb_hub_initfn(USBDevice *dev)
USBHubPort *port;
int i;

if (dev->port->hubcount == 5) {
error_report("usb hub chain too deep");
return -1;
}

usb_desc_create_serial(dev);
usb_desc_init(dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
Expand Down
28 changes: 12 additions & 16 deletions hw/usb/hcd-xhci.c
Expand Up @@ -452,7 +452,6 @@ struct XHCIState {
MemoryRegion mem_oper;
MemoryRegion mem_runtime;
MemoryRegion mem_doorbell;
const char *name;
unsigned int devaddr;

/* properties */
Expand Down Expand Up @@ -1172,8 +1171,6 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
uint32_t ctx[5];
uint32_t ctx2[2];

fprintf(stderr, "%s: epid %d, state %d\n",
__func__, epctx->epid, state);
xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
ctx[0] &= ~EP_STATE_MASK;
ctx[0] |= state;
Expand Down Expand Up @@ -2568,7 +2565,7 @@ static void xhci_process_commands(XHCIState *xhci)
}
break;
default:
fprintf(stderr, "xhci: unimplemented command %d\n", type);
trace_usb_xhci_unimplemented("command", type);
event.ccode = CC_TRB_ERROR;
break;
}
Expand Down Expand Up @@ -2767,7 +2764,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
ret = 0x00000000; /* reserved */
break;
default:
fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg);
trace_usb_xhci_unimplemented("cap read", reg);
ret = 0;
}

Expand All @@ -2790,8 +2787,7 @@ static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size)
break;
case 0x0c: /* reserved */
default:
fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
port->portnr, (uint32_t)reg);
trace_usb_xhci_unimplemented("port read", reg);
ret = 0;
}

Expand Down Expand Up @@ -2831,8 +2827,7 @@ static void xhci_port_write(void *ptr, hwaddr reg,
case 0x04: /* PORTPMSC */
case 0x08: /* PORTLI */
default:
fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n",
port->portnr, (uint32_t)reg);
trace_usb_xhci_unimplemented("port write", reg);
}
}

Expand Down Expand Up @@ -2870,7 +2865,7 @@ static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size)
ret = xhci->config;
break;
default:
fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg);
trace_usb_xhci_unimplemented("oper read", reg);
ret = 0;
}

Expand Down Expand Up @@ -2935,7 +2930,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg,
xhci->config = val & 0xff;
break;
default:
fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg);
trace_usb_xhci_unimplemented("oper write", reg);
}
}

Expand All @@ -2951,8 +2946,7 @@ static uint64_t xhci_runtime_read(void *ptr, hwaddr reg,
ret = xhci_mfindex_get(xhci) & 0x3fff;
break;
default:
fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n",
(int)reg);
trace_usb_xhci_unimplemented("runtime read", reg);
break;
}
} else {
Expand Down Expand Up @@ -2996,7 +2990,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
trace_usb_xhci_runtime_write(reg, val);

if (reg < 0x20) {
fprintf(stderr, "%s: reg 0x%x unimplemented\n", __func__, (int)reg);
trace_usb_xhci_unimplemented("runtime write", reg);
return;
}

Expand Down Expand Up @@ -3038,8 +3032,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
xhci_events_update(xhci, v);
break;
default:
fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n",
(int)reg);
trace_usb_xhci_unimplemented("oper write", reg);
}
}

Expand Down Expand Up @@ -3290,6 +3283,9 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
if (xhci->numintrs > MAXINTRS) {
xhci->numintrs = MAXINTRS;
}
while (xhci->numintrs & (xhci->numintrs - 1)) { /* ! power of 2 */
xhci->numintrs++;
}
if (xhci->numintrs < 1) {
xhci->numintrs = 1;
}
Expand Down
37 changes: 36 additions & 1 deletion hw/usb/redirect.c
Expand Up @@ -104,6 +104,8 @@ struct USBRedirDevice {
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
const uint8_t *read_buf;
int read_buf_size;
/* Active chardev-watch-tag */
guint watch;
/* For async handling of close */
QEMUBH *chardev_close_bh;
/* To delay the usb attach in case of quick chardev close + open */
Expand Down Expand Up @@ -254,9 +256,21 @@ static int usbredir_read(void *priv, uint8_t *data, int count)
return count;
}

static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
void *opaque)
{
USBRedirDevice *dev = opaque;

dev->watch = 0;
usbredirparser_do_write(dev->parser);

return FALSE;
}

static int usbredir_write(void *priv, uint8_t *data, int count)
{
USBRedirDevice *dev = priv;
int r;

if (!dev->cs->be_open) {
return 0;
Expand All @@ -267,7 +281,17 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
return 0;
}

return qemu_chr_fe_write(dev->cs, data, count);
r = qemu_chr_fe_write(dev->cs, data, count);
if (r < count) {
if (!dev->watch) {
dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT,
usbredir_write_unblocked, dev);
}
if (r < 0) {
r = 0;
}
}
return r;
}

/*
Expand Down Expand Up @@ -1085,6 +1109,10 @@ static void usbredir_chardev_close_bh(void *opaque)
usbredirparser_destroy(dev->parser);
dev->parser = NULL;
}
if (dev->watch) {
g_source_remove(dev->watch);
dev->watch = 0;
}
}

static void usbredir_create_parser(USBRedirDevice *dev)
Expand Down Expand Up @@ -1317,6 +1345,9 @@ static void usbredir_handle_destroy(USBDevice *udev)
if (dev->parser) {
usbredirparser_destroy(dev->parser);
}
if (dev->watch) {
g_source_remove(dev->watch);
}

free(dev->filter_rules);
}
Expand Down Expand Up @@ -1973,6 +2004,10 @@ static int usbredir_post_load(void *priv, int version_id)
{
USBRedirDevice *dev = priv;

if (dev->parser == NULL) {
return 0;
}

switch (dev->device_info.speed) {
case usb_redir_speed_low:
dev->dev.speed = USB_SPEED_LOW;
Expand Down
1 change: 1 addition & 0 deletions trace-events
Expand Up @@ -380,6 +380,7 @@ usb_xhci_xfer_nak(void *xfer) "%p"
usb_xhci_xfer_retry(void *xfer) "%p"
usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d"
usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)"

# hw/usb/desc.c
usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
Expand Down

0 comments on commit 2a7a239

Please sign in to comment.