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

# 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
This commit is contained in:
Anthony Liguori 2013-04-08 10:36:40 -05:00
commit 2a7a239ff0
8 changed files with 74 additions and 29 deletions

View File

@ -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
@ -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
@ -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.
@ -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,

View File

@ -337,6 +337,7 @@ typedef struct USBPortOps {
struct USBPort {
USBDevice *dev;
int speedmask;
int hubcount;
char path[16];
USBPortOps *ops;
void *opaque;

View File

@ -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;
}
}

View File

@ -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,

View File

@ -25,6 +25,7 @@
#include "trace.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
#include "qemu/error-report.h"
#define NUM_PORTS 8
@ -32,6 +33,7 @@ typedef struct USBHubPort {
USBPort port;
uint16_t wPortStatus;
uint16_t wPortChange;
uint16_t wPortChange_reported;
} USBHubPort;
typedef struct USBHubState {
@ -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++) {
@ -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);

View File

@ -452,7 +452,6 @@ struct XHCIState {
MemoryRegion mem_oper;
MemoryRegion mem_runtime;
MemoryRegion mem_doorbell;
const char *name;
unsigned int devaddr;
/* properties */
@ -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;
@ -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;
}
@ -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;
}
@ -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;
}
@ -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);
}
}
@ -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;
}
@ -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);
}
}
@ -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 {
@ -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;
}
@ -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);
}
}
@ -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;
}

View File

@ -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 */
@ -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;
@ -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;
}
/*
@ -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)
@ -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);
}
@ -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;

View File

@ -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"