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

# By Gerd Hoffmann
# Via Gerd Hoffmann
* kraxel/usb.78:
  uas-uas: usb3 streams
  usb-xhci: usb3 streams
  usb-core: usb3 streams
  usb: fix endpoint descriptor ordering
  usb-redir: simplify packet copy
  usb: make usb_packet_copy operate on combined packets
  usb: add usb_ep_set_halted
  usb-host: remove usb_host_device_close
  usb-host: move legacy cmd line bits
  usb-storage: use scsi_req_enqueue return value
  allow disabling usb smartcard support
  make usb devices configurable
  fix scripts/make_device_config.sh
  usb: Makefile cleanup
This commit is contained in:
Anthony Liguori 2013-02-21 09:39:17 -06:00
commit 70aa41b56c
44 changed files with 742 additions and 291 deletions

2
configure vendored
View File

@ -3723,7 +3723,7 @@ fi
# USB host support # USB host support
case "$usb" in case "$usb" in
linux) linux)
echo "HOST_USB=linux" >> $config_host_mak echo "HOST_USB=linux legacy" >> $config_host_mak
;; ;;
bsd) bsd)
echo "HOST_USB=bsd" >> $config_host_mak echo "HOST_USB=bsd" >> $config_host_mak

View File

@ -1,6 +1,7 @@
# Default configuration for alpha-softmmu # Default configuration for alpha-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_SERIAL=y CONFIG_SERIAL=y
CONFIG_I8254=y CONFIG_I8254=y
CONFIG_PCKBD=y CONFIG_PCKBD=y

View File

@ -1,6 +1,7 @@
# Default configuration for arm-softmmu # Default configuration for arm-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_VGA=y CONFIG_VGA=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y

View File

@ -1,6 +1,7 @@
# Default configuration for i386-softmmu # Default configuration for i386-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_VGA=y CONFIG_VGA=y
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y CONFIG_VGA_ISA=y

View File

@ -1,5 +1,6 @@
# Default configuration for m68k-softmmu # Default configuration for m68k-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_PTIMER=y CONFIG_PTIMER=y

View File

@ -1,6 +1,7 @@
# Default configuration for mips-softmmu # Default configuration for mips-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA=y CONFIG_VGA=y

View File

@ -1,6 +1,7 @@
# Default configuration for mips64-softmmu # Default configuration for mips64-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA=y CONFIG_VGA=y

View File

@ -1,6 +1,7 @@
# Default configuration for mips64el-softmmu # Default configuration for mips64el-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA=y CONFIG_VGA=y

View File

@ -1,6 +1,7 @@
# Default configuration for mipsel-softmmu # Default configuration for mipsel-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA=y CONFIG_VGA=y

View File

@ -1,6 +1,7 @@
# Default configuration for ppc-softmmu # Default configuration for ppc-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESCC=y CONFIG_ESCC=y

View File

@ -1,6 +1,7 @@
# Default configuration for ppc64-softmmu # Default configuration for ppc64-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESCC=y CONFIG_ESCC=y

View File

@ -1,6 +1,7 @@
# Default configuration for ppcemb-softmmu # Default configuration for ppcemb-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESCC=y CONFIG_ESCC=y

View File

@ -1,6 +1,7 @@
# Default configuration for sh4-softmmu # Default configuration for sh4-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_SERIAL=y CONFIG_SERIAL=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y

View File

@ -1,6 +1,7 @@
# Default configuration for sh4eb-softmmu # Default configuration for sh4eb-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_SERIAL=y CONFIG_SERIAL=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y

View File

@ -1,6 +1,7 @@
# Default configuration for sparc64-softmmu # Default configuration for sparc64-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_M48T59=y CONFIG_M48T59=y
CONFIG_PTIMER=y CONFIG_PTIMER=y

8
default-configs/usb.mak Normal file
View File

@ -0,0 +1,8 @@
CONFIG_USB_TABLET_WACOM=y
CONFIG_USB_STORAGE_BOT=y
CONFIG_USB_STORAGE_UAS=y
CONFIG_USB_SMARTCARD=y
CONFIG_USB_AUDIO=y
CONFIG_USB_SERIAL=y
CONFIG_USB_NETWORK=y
CONFIG_USB_BLUETOOTH=y

View File

@ -1,6 +1,7 @@
# Default configuration for x86_64-softmmu # Default configuration for x86_64-softmmu
include pci.mak include pci.mak
include usb.mak
CONFIG_VGA=y CONFIG_VGA=y
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y CONFIG_VGA_ISA=y

View File

@ -38,8 +38,10 @@ common-obj-$(CONFIG_DMA) += dma.o
common-obj-$(CONFIG_I82374) += i82374.o common-obj-$(CONFIG_I82374) += i82374.o
common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_HPET) += hpet.o
common-obj-$(CONFIG_APPLESMC) += applesmc.o common-obj-$(CONFIG_APPLESMC) += applesmc.o
ifeq ($(CONFIG_USB_SMARTCARD),y)
common-obj-y += ccid-card-passthru.o common-obj-y += ccid-card-passthru.o
common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
endif
common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
common-obj-y += fifo.o common-obj-y += fifo.o
common-obj-y += pam.o common-obj-y += pam.o

View File

@ -361,6 +361,7 @@ struct USBPacket {
int pid; int pid;
uint64_t id; uint64_t id;
USBEndpoint *ep; USBEndpoint *ep;
unsigned int stream;
QEMUIOVector iov; QEMUIOVector iov;
uint64_t parameter; /* control transfers */ uint64_t parameter; /* control transfers */
bool short_not_ok; bool short_not_ok;
@ -383,13 +384,15 @@ struct USBCombinedPacket {
void usb_packet_init(USBPacket *p); void usb_packet_init(USBPacket *p);
void usb_packet_set_state(USBPacket *p, USBPacketState state); void usb_packet_set_state(USBPacket *p, USBPacketState state);
void usb_packet_check_state(USBPacket *p, USBPacketState expected); void usb_packet_check_state(USBPacket *p, USBPacketState expected);
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id, void usb_packet_setup(USBPacket *p, int pid,
bool short_not_ok, bool int_req); USBEndpoint *ep, unsigned int stream,
uint64_t id, bool short_not_ok, bool int_req);
void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len); void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
int usb_packet_map(USBPacket *p, QEMUSGList *sgl); int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl); void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl);
void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes); void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
void usb_packet_skip(USBPacket *p, size_t bytes); void usb_packet_skip(USBPacket *p, size_t bytes);
size_t usb_packet_size(USBPacket *p);
void usb_packet_cleanup(USBPacket *p); void usb_packet_cleanup(USBPacket *p);
static inline bool usb_packet_is_inflight(USBPacket *p) static inline bool usb_packet_is_inflight(USBPacket *p)
@ -417,6 +420,7 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
uint16_t raw); uint16_t raw);
int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep); int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled); void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted);
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
uint64_t id); uint64_t id);
@ -428,13 +432,12 @@ void usb_attach(USBPort *port);
void usb_detach(USBPort *port); void usb_detach(USBPort *port);
void usb_port_reset(USBPort *port); void usb_port_reset(USBPort *port);
void usb_device_reset(USBDevice *dev); void usb_device_reset(USBDevice *dev);
void usb_wakeup(USBEndpoint *ep); void usb_wakeup(USBEndpoint *ep, unsigned int stream);
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p); void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
int set_usb_string(uint8_t *buf, const char *str); int set_usb_string(uint8_t *buf, const char *str);
/* usb-linux.c */ /* usb-linux.c */
USBDevice *usb_host_device_open(USBBus *bus, const char *devname); USBDevice *usb_host_device_open(USBBus *bus, const char *devname);
int usb_host_device_close(const char *devname);
void usb_host_info(Monitor *mon, const QDict *qdict); void usb_host_info(Monitor *mon, const QDict *qdict);
/* usb-bt.c */ /* usb-bt.c */
@ -488,7 +491,7 @@ struct USBBus {
struct USBBusOps { struct USBBusOps {
int (*register_companion)(USBBus *bus, USBPort *ports[], int (*register_companion)(USBBus *bus, USBPort *ports[],
uint32_t portcount, uint32_t firstport); uint32_t portcount, uint32_t firstport);
void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep); void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep, unsigned int stream);
}; };
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host); void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);

View File

@ -1,14 +1,30 @@
# usb subsystem core
common-obj-y += core.o combined-packet.o bus.o desc.o
common-obj-y += libhw.o
# usb host adapters
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
common-obj-y += libhw.o
# emulated usb devices
common-obj-y += dev-hub.o
common-obj-y += dev-hid.o
common-obj-$(CONFIG_USB_TABLET_WACOM) += dev-wacom.o
common-obj-$(CONFIG_USB_STORAGE_BOT) += dev-storage.o
common-obj-$(CONFIG_USB_STORAGE_UAS) += dev-uas.o
common-obj-$(CONFIG_USB_AUDIO) += dev-audio.o
common-obj-$(CONFIG_USB_SERIAL) += dev-serial.o
common-obj-$(CONFIG_USB_NETWORK) += dev-network.o
# FIXME: make configurable too
CONFIG_USB_BLUETOOTH := y
common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o
common-obj-$(CONFIG_USB_SMARTCARD) += dev-smartcard-reader.o
# usb redirection
common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o # usb pass-through
common-obj-y += host-$(HOST_USB).o dev-bluetooth.o common-obj-y += $(patsubst %,host-%.o,$(HOST_USB))
common-obj-y += dev-hid.o dev-storage.o dev-wacom.o
common-obj-y += dev-serial.o dev-network.o dev-audio.o
common-obj-y += dev-smartcard-reader.o
common-obj-y += dev-uas.o

View File

@ -71,7 +71,7 @@ void usb_device_reset(USBDevice *dev)
usb_device_handle_reset(dev); usb_device_handle_reset(dev);
} }
void usb_wakeup(USBEndpoint *ep) void usb_wakeup(USBEndpoint *ep, unsigned int stream)
{ {
USBDevice *dev = ep->dev; USBDevice *dev = ep->dev;
USBBus *bus = usb_bus_from_device(dev); USBBus *bus = usb_bus_from_device(dev);
@ -80,7 +80,7 @@ void usb_wakeup(USBEndpoint *ep)
dev->port->ops->wakeup(dev->port); dev->port->ops->wakeup(dev->port);
} }
if (bus->ops->wakeup_endpoint) { if (bus->ops->wakeup_endpoint) {
bus->ops->wakeup_endpoint(bus, ep); bus->ops->wakeup_endpoint(bus, ep, stream);
} }
} }
@ -545,14 +545,16 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
p->state = state; p->state = state;
} }
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id, void usb_packet_setup(USBPacket *p, int pid,
bool short_not_ok, bool int_req) USBEndpoint *ep, unsigned int stream,
uint64_t id, bool short_not_ok, bool int_req)
{ {
assert(!usb_packet_is_inflight(p)); assert(!usb_packet_is_inflight(p));
assert(p->iov.iov != NULL); assert(p->iov.iov != NULL);
p->id = id; p->id = id;
p->pid = pid; p->pid = pid;
p->ep = ep; p->ep = ep;
p->stream = stream;
p->status = USB_RET_SUCCESS; p->status = USB_RET_SUCCESS;
p->actual_length = 0; p->actual_length = 0;
p->parameter = 0; p->parameter = 0;
@ -570,15 +572,17 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes) void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
{ {
QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
assert(p->actual_length >= 0); assert(p->actual_length >= 0);
assert(p->actual_length + bytes <= p->iov.size); assert(p->actual_length + bytes <= iov->size);
switch (p->pid) { switch (p->pid) {
case USB_TOKEN_SETUP: case USB_TOKEN_SETUP:
case USB_TOKEN_OUT: case USB_TOKEN_OUT:
iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
break; break;
case USB_TOKEN_IN: case USB_TOKEN_IN:
iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
break; break;
default: default:
fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid); fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
@ -589,14 +593,21 @@ void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
void usb_packet_skip(USBPacket *p, size_t bytes) void usb_packet_skip(USBPacket *p, size_t bytes)
{ {
QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
assert(p->actual_length >= 0); assert(p->actual_length >= 0);
assert(p->actual_length + bytes <= p->iov.size); assert(p->actual_length + bytes <= iov->size);
if (p->pid == USB_TOKEN_IN) { if (p->pid == USB_TOKEN_IN) {
iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes); iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes);
} }
p->actual_length += bytes; p->actual_length += bytes;
} }
size_t usb_packet_size(USBPacket *p)
{
return p->combined ? p->combined->iov.size : p->iov.size;
}
void usb_packet_cleanup(USBPacket *p) void usb_packet_cleanup(USBPacket *p)
{ {
assert(!usb_packet_is_inflight(p)); assert(!usb_packet_is_inflight(p));
@ -755,6 +766,12 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled)
uep->pipeline = enabled; uep->pipeline = enabled;
} }
void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted)
{
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
uep->halted = halted;
}
USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
uint64_t id) uint64_t id)
{ {

View File

@ -225,12 +225,9 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
d->u.endpoint.bRefresh = ep->bRefresh; d->u.endpoint.bRefresh = ep->bRefresh;
d->u.endpoint.bSynchAddress = ep->bSynchAddress; d->u.endpoint.bSynchAddress = ep->bSynchAddress;
} }
if (ep->extra) {
memcpy(dest + bLength, ep->extra, extralen);
}
if (superlen) { if (superlen) {
USBDescriptor *d = (void *)(dest + bLength + extralen); USBDescriptor *d = (void *)(dest + bLength);
d->bLength = 0x06; d->bLength = 0x06;
d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; d->bDescriptorType = USB_DT_ENDPOINT_COMPANION;
@ -243,6 +240,10 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
usb_hi(ep->wBytesPerInterval); usb_hi(ep->wBytesPerInterval);
} }
if (ep->extra) {
memcpy(dest + bLength + superlen, ep->extra, extralen);
}
return bLength + extralen + superlen; return bLength + extralen + superlen;
} }

View File

@ -478,7 +478,7 @@ static void usb_bt_out_hci_packet_event(void *opaque,
struct USBBtState *s = (struct USBBtState *) opaque; struct USBBtState *s = (struct USBBtState *) opaque;
if (s->evt.len == 0) { if (s->evt.len == 0) {
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
usb_bt_fifo_enqueue(&s->evt, data, len); usb_bt_fifo_enqueue(&s->evt, data, len);
} }

View File

@ -423,7 +423,7 @@ static void usb_hid_changed(HIDState *hs)
{ {
USBHIDState *us = container_of(hs, USBHIDState, hid); USBHIDState *us = container_of(hs, USBHIDState, hid);
usb_wakeup(us->intr); usb_wakeup(us->intr, 0);
} }
static void usb_hid_handle_reset(USBDevice *dev) static void usb_hid_handle_reset(USBDevice *dev)

View File

@ -164,7 +164,7 @@ static void usb_hub_attach(USBPort *port1)
} else { } else {
port->wPortStatus &= ~PORT_STAT_LOW_SPEED; port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
} }
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
static void usb_hub_detach(USBPort *port1) static void usb_hub_detach(USBPort *port1)
@ -173,7 +173,7 @@ static void usb_hub_detach(USBPort *port1)
USBHubPort *port = &s->ports[port1->index]; USBHubPort *port = &s->ports[port1->index];
trace_usb_hub_detach(s->dev.addr, port1->index + 1); trace_usb_hub_detach(s->dev.addr, port1->index + 1);
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
/* Let upstream know the device on this port is gone */ /* Let upstream know the device on this port is gone */
s->dev.port->ops->child_detach(s->dev.port, port1->dev); s->dev.port->ops->child_detach(s->dev.port, port1->dev);
@ -184,7 +184,7 @@ static void usb_hub_detach(USBPort *port1)
port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE;
} }
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
static void usb_hub_child_detach(USBPort *port1, USBDevice *child) static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
@ -202,7 +202,7 @@ static void usb_hub_wakeup(USBPort *port1)
if (port->wPortStatus & PORT_STAT_SUSPEND) { if (port->wPortStatus & PORT_STAT_SUSPEND) {
port->wPortChange |= PORT_STAT_C_SUSPEND; port->wPortChange |= PORT_STAT_C_SUSPEND;
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
} }
@ -364,7 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
port->wPortChange |= PORT_STAT_C_RESET; port->wPortChange |= PORT_STAT_C_RESET;
/* set enable bit */ /* set enable bit */
port->wPortStatus |= PORT_STAT_ENABLE; port->wPortStatus |= PORT_STAT_ENABLE;
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
break; break;
case PORT_POWER: case PORT_POWER:

View File

@ -855,7 +855,7 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length)
g_malloc0(sizeof(struct rndis_response) + length); g_malloc0(sizeof(struct rndis_response) + length);
if (QTAILQ_EMPTY(&s->rndis_resp)) { if (QTAILQ_EMPTY(&s->rndis_resp)) {
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);

View File

@ -839,7 +839,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full)
s->bmSlotICCState |= SLOT_0_CHANGED_MASK; s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
} }
s->notify_slot_change = true; s->notify_slot_change = true;
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
static void ccid_write_data_block_error( static void ccid_write_data_block_error(

View File

@ -400,6 +400,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
struct usb_msd_cbw cbw; struct usb_msd_cbw cbw;
uint8_t devep = p->ep->nr; uint8_t devep = p->ep->nr;
SCSIDevice *scsi_dev; SCSIDevice *scsi_dev;
uint32_t len;
switch (p->pid) { switch (p->pid) {
case USB_TOKEN_OUT: case USB_TOKEN_OUT:
@ -441,8 +442,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
#ifdef DEBUG_MSD #ifdef DEBUG_MSD
scsi_req_print(s->req); scsi_req_print(s->req);
#endif #endif
scsi_req_enqueue(s->req); len = scsi_req_enqueue(s->req);
if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { if (len) {
scsi_req_continue(s->req); scsi_req_continue(s->req);
} }
break; break;

View File

@ -99,6 +99,9 @@ typedef struct {
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
#define UAS_STREAM_BM_ATTR 4
#define UAS_MAX_STREAMS (1 << UAS_STREAM_BM_ATTR)
typedef struct UASDevice UASDevice; typedef struct UASDevice UASDevice;
typedef struct UASRequest UASRequest; typedef struct UASRequest UASRequest;
typedef struct UASStatus UASStatus; typedef struct UASStatus UASStatus;
@ -106,12 +109,18 @@ typedef struct UASStatus UASStatus;
struct UASDevice { struct UASDevice {
USBDevice dev; USBDevice dev;
SCSIBus bus; SCSIBus bus;
UASRequest *datain;
UASRequest *dataout;
USBPacket *status;
QEMUBH *status_bh; QEMUBH *status_bh;
QTAILQ_HEAD(, UASStatus) results; QTAILQ_HEAD(, UASStatus) results;
QTAILQ_HEAD(, UASRequest) requests; QTAILQ_HEAD(, UASRequest) requests;
/* usb 2.0 only */
USBPacket *status2;
UASRequest *datain2;
UASRequest *dataout2;
/* usb 3.0 only */
USBPacket *data3[UAS_MAX_STREAMS];
USBPacket *status3[UAS_MAX_STREAMS];
}; };
struct UASRequest { struct UASRequest {
@ -132,6 +141,7 @@ struct UASRequest {
}; };
struct UASStatus { struct UASStatus {
uint32_t stream;
uas_ui status; uas_ui status;
uint32_t length; uint32_t length;
QTAILQ_ENTRY(UASStatus) next; QTAILQ_ENTRY(UASStatus) next;
@ -144,6 +154,7 @@ enum {
STR_PRODUCT, STR_PRODUCT,
STR_SERIALNUMBER, STR_SERIALNUMBER,
STR_CONFIG_HIGH, STR_CONFIG_HIGH,
STR_CONFIG_SUPER,
}; };
static const USBDescStrings desc_strings = { static const USBDescStrings desc_strings = {
@ -151,6 +162,7 @@ static const USBDescStrings desc_strings = {
[STR_PRODUCT] = "USB Attached SCSI HBA", [STR_PRODUCT] = "USB Attached SCSI HBA",
[STR_SERIALNUMBER] = "27842", [STR_SERIALNUMBER] = "27842",
[STR_CONFIG_HIGH] = "High speed config (usb 2.0)", [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
[STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
}; };
static const USBDescIface desc_iface_high = { static const USBDescIface desc_iface_high = {
@ -204,6 +216,64 @@ static const USBDescIface desc_iface_high = {
} }
}; };
static const USBDescIface desc_iface_super = {
.bInterfaceNumber = 0,
.bNumEndpoints = 4,
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
.bInterfaceSubClass = 0x06, /* SCSI */
.bInterfaceProtocol = 0x62, /* UAS */
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 1024,
.bMaxBurst = 15,
.extra = (uint8_t[]) {
0x04, /* u8 bLength */
0x24, /* u8 bDescriptorType */
UAS_PIPE_ID_COMMAND,
0x00, /* u8 bReserved */
},
},{
.bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 1024,
.bMaxBurst = 15,
.bmAttributes_super = UAS_STREAM_BM_ATTR,
.extra = (uint8_t[]) {
0x04, /* u8 bLength */
0x24, /* u8 bDescriptorType */
UAS_PIPE_ID_STATUS,
0x00, /* u8 bReserved */
},
},{
.bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 1024,
.bMaxBurst = 15,
.bmAttributes_super = UAS_STREAM_BM_ATTR,
.extra = (uint8_t[]) {
0x04, /* u8 bLength */
0x24, /* u8 bDescriptorType */
UAS_PIPE_ID_DATA_IN,
0x00, /* u8 bReserved */
},
},{
.bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 1024,
.bMaxBurst = 15,
.bmAttributes_super = UAS_STREAM_BM_ATTR,
.extra = (uint8_t[]) {
0x04, /* u8 bLength */
0x24, /* u8 bDescriptorType */
UAS_PIPE_ID_DATA_OUT,
0x00, /* u8 bReserved */
},
},
}
};
static const USBDescDevice desc_device_high = { static const USBDescDevice desc_device_high = {
.bcdUSB = 0x0200, .bcdUSB = 0x0200,
.bMaxPacketSize0 = 64, .bMaxPacketSize0 = 64,
@ -220,6 +290,22 @@ static const USBDescDevice desc_device_high = {
}, },
}; };
static const USBDescDevice desc_device_super = {
.bcdUSB = 0x0300,
.bMaxPacketSize0 = 64,
.bNumConfigurations = 1,
.confs = (USBDescConfig[]) {
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG_SUPER,
.bmAttributes = 0xc0,
.nif = 1,
.ifs = &desc_iface_super,
},
},
};
static const USBDesc desc = { static const USBDesc desc = {
.id = { .id = {
.idVendor = 0x46f4, /* CRC16() of "QEMU" */ .idVendor = 0x46f4, /* CRC16() of "QEMU" */
@ -229,45 +315,68 @@ static const USBDesc desc = {
.iProduct = STR_PRODUCT, .iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER, .iSerialNumber = STR_SERIALNUMBER,
}, },
.high = &desc_device_high, .high = &desc_device_high,
.str = desc_strings, .super = &desc_device_super,
.str = desc_strings,
}; };
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static UASStatus *usb_uas_alloc_status(uint8_t id, uint16_t tag) static bool uas_using_streams(UASDevice *uas)
{
return uas->dev.speed == USB_SPEED_SUPER;
}
/* --------------------------------------------------------------------- */
static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
{ {
UASStatus *st = g_new0(UASStatus, 1); UASStatus *st = g_new0(UASStatus, 1);
st->status.hdr.id = id; st->status.hdr.id = id;
st->status.hdr.tag = cpu_to_be16(tag); st->status.hdr.tag = cpu_to_be16(tag);
st->length = sizeof(uas_ui_header); st->length = sizeof(uas_ui_header);
if (uas_using_streams(uas)) {
st->stream = tag;
}
return st; return st;
} }
static void usb_uas_send_status_bh(void *opaque) static void usb_uas_send_status_bh(void *opaque)
{ {
UASDevice *uas = opaque; UASDevice *uas = opaque;
UASStatus *st = QTAILQ_FIRST(&uas->results); UASStatus *st;
USBPacket *p = uas->status; USBPacket *p;
assert(p != NULL); while ((st = QTAILQ_FIRST(&uas->results)) != NULL) {
assert(st != NULL); if (uas_using_streams(uas)) {
p = uas->status3[st->stream];
uas->status3[st->stream] = NULL;
} else {
p = uas->status2;
uas->status2 = NULL;
}
if (p == NULL) {
break;
}
uas->status = NULL; usb_packet_copy(p, &st->status, st->length);
usb_packet_copy(p, &st->status, st->length); QTAILQ_REMOVE(&uas->results, st, next);
QTAILQ_REMOVE(&uas->results, st, next); g_free(st);
g_free(st);
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
usb_packet_complete(&uas->dev, p); usb_packet_complete(&uas->dev, p);
}
} }
static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length) static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
{ {
USBPacket *p = uas_using_streams(uas) ?
uas->status3[st->stream] : uas->status2;
st->length += length; st->length += length;
QTAILQ_INSERT_TAIL(&uas->results, st, next); QTAILQ_INSERT_TAIL(&uas->results, st, next);
if (uas->status) { if (p) {
/* /*
* Just schedule bh make sure any in-flight data transaction * Just schedule bh make sure any in-flight data transaction
* is finished before completing (sending) the status packet. * is finished before completing (sending) the status packet.
@ -276,14 +385,14 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
} else { } else {
USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN, USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN,
UAS_PIPE_ID_STATUS); UAS_PIPE_ID_STATUS);
usb_wakeup(ep); usb_wakeup(ep, st->stream);
} }
} }
static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
uint8_t code, uint16_t add_info) uint8_t code, uint16_t add_info)
{ {
UASStatus *st = usb_uas_alloc_status(UAS_UI_RESPONSE, tag); UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
trace_usb_uas_response(uas->dev.addr, tag, code); trace_usb_uas_response(uas->dev.addr, tag, code);
st->status.response.response_code = code; st->status.response.response_code = code;
@ -293,7 +402,7 @@ static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
static void usb_uas_queue_sense(UASRequest *req, uint8_t status) static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
{ {
UASStatus *st = usb_uas_alloc_status(UAS_UI_SENSE, req->tag); UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag);
int len, slen = 0; int len, slen = 0;
trace_usb_uas_sense(req->uas->dev.addr, req->tag, status); trace_usb_uas_sense(req->uas->dev.addr, req->tag, status);
@ -310,7 +419,8 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
static void usb_uas_queue_read_ready(UASRequest *req) static void usb_uas_queue_read_ready(UASRequest *req)
{ {
UASStatus *st = usb_uas_alloc_status(UAS_UI_READ_READY, req->tag); UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
req->tag);
trace_usb_uas_read_ready(req->uas->dev.addr, req->tag); trace_usb_uas_read_ready(req->uas->dev.addr, req->tag);
usb_uas_queue_status(req->uas, st, 0); usb_uas_queue_status(req->uas, st, 0);
@ -318,7 +428,8 @@ static void usb_uas_queue_read_ready(UASRequest *req)
static void usb_uas_queue_write_ready(UASRequest *req) static void usb_uas_queue_write_ready(UASRequest *req)
{ {
UASStatus *st = usb_uas_alloc_status(UAS_UI_WRITE_READY, req->tag); UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY,
req->tag);
trace_usb_uas_write_ready(req->uas->dev.addr, req->tag); trace_usb_uas_write_ready(req->uas->dev.addr, req->tag);
usb_uas_queue_status(req->uas, st, 0); usb_uas_queue_status(req->uas, st, 0);
@ -381,18 +492,22 @@ static void usb_uas_start_next_transfer(UASDevice *uas)
{ {
UASRequest *req; UASRequest *req;
if (uas_using_streams(uas)) {
return;
}
QTAILQ_FOREACH(req, &uas->requests, next) { QTAILQ_FOREACH(req, &uas->requests, next) {
if (req->active || req->complete) { if (req->active || req->complete) {
continue; continue;
} }
if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain == NULL) { if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) {
uas->datain = req; uas->datain2 = req;
usb_uas_queue_read_ready(req); usb_uas_queue_read_ready(req);
req->active = true; req->active = true;
return; return;
} }
if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout == NULL) { if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) {
uas->dataout = req; uas->dataout2 = req;
usb_uas_queue_write_ready(req); usb_uas_queue_write_ready(req);
req->active = true; req->active = true;
return; return;
@ -417,11 +532,11 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
UASRequest *req = priv; UASRequest *req = priv;
UASDevice *uas = req->uas; UASDevice *uas = req->uas;
if (req == uas->datain) { if (req == uas->datain2) {
uas->datain = NULL; uas->datain2 = NULL;
} }
if (req == uas->dataout) { if (req == uas->dataout2) {
uas->dataout = NULL; uas->dataout2 = NULL;
} }
QTAILQ_REMOVE(&uas->requests, req, next); QTAILQ_REMOVE(&uas->requests, req, next);
g_free(req); g_free(req);
@ -522,12 +637,25 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
{ {
UASDevice *uas = DO_UPCAST(UASDevice, dev, dev); UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
UASRequest *req, *nreq; UASRequest *req, *nreq;
int i;
if (uas->status == p) { if (uas->status2 == p) {
uas->status = NULL; uas->status2 = NULL;
qemu_bh_cancel(uas->status_bh); qemu_bh_cancel(uas->status_bh);
return; return;
} }
if (uas_using_streams(uas)) {
for (i = 0; i < UAS_MAX_STREAMS; i++) {
if (uas->status3[i] == p) {
uas->status3[i] = NULL;
return;
}
if (uas->data3[i] == p) {
uas->data3[i] = NULL;
return;
}
}
}
QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) { QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
if (req->data == p) { if (req->data == p) {
req->data = NULL; req->data = NULL;
@ -555,9 +683,18 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui)
usb_uas_get_lun(req->lun), usb_uas_get_lun(req->lun),
req->lun >> 32, req->lun & 0xffffffff); req->lun >> 32, req->lun & 0xffffffff);
QTAILQ_INSERT_TAIL(&uas->requests, req, next); QTAILQ_INSERT_TAIL(&uas->requests, req, next);
if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) {
req->data = uas->data3[req->tag];
req->data_async = true;
uas->data3[req->tag] = NULL;
}
req->req = scsi_req_new(req->dev, req->tag, req->req = scsi_req_new(req->dev, req->tag,
usb_uas_get_lun(req->lun), usb_uas_get_lun(req->lun),
ui->command.cdb, req); ui->command.cdb, req);
#if 1
scsi_req_print(req->req);
#endif
len = scsi_req_enqueue(req->req); len = scsi_req_enqueue(req->req);
if (len) { if (len) {
req->data_size = len; req->data_size = len;
@ -669,12 +806,26 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
} }
break; break;
case UAS_PIPE_ID_STATUS: case UAS_PIPE_ID_STATUS:
st = QTAILQ_FIRST(&uas->results); if (p->stream) {
if (st == NULL) { QTAILQ_FOREACH(st, &uas->results, next) {
assert(uas->status == NULL); if (st->stream == p->stream) {
uas->status = p; break;
p->status = USB_RET_ASYNC; }
break; }
if (st == NULL) {
assert(uas->status3[p->stream] == NULL);
uas->status3[p->stream] = p;
p->status = USB_RET_ASYNC;
break;
}
} else {
st = QTAILQ_FIRST(&uas->results);
if (st == NULL) {
assert(uas->status2 == NULL);
uas->status2 = p;
p->status = USB_RET_ASYNC;
break;
}
} }
usb_packet_copy(p, &st->status, st->length); usb_packet_copy(p, &st->status, st->length);
QTAILQ_REMOVE(&uas->results, st, next); QTAILQ_REMOVE(&uas->results, st, next);
@ -682,11 +833,23 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
break; break;
case UAS_PIPE_ID_DATA_IN: case UAS_PIPE_ID_DATA_IN:
case UAS_PIPE_ID_DATA_OUT: case UAS_PIPE_ID_DATA_OUT:
req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout; if (p->stream) {
req = usb_uas_find_request(uas, p->stream);
} else {
req = (p->ep->nr == UAS_PIPE_ID_DATA_IN)
? uas->datain2 : uas->dataout2;
}
if (req == NULL) { if (req == NULL) {
fprintf(stderr, "%s: no inflight request\n", __func__); if (p->stream) {
p->status = USB_RET_STALL; assert(uas->data3[p->stream] == NULL);
break; uas->data3[p->stream] = p;
p->status = USB_RET_ASYNC;
break;
} else {
fprintf(stderr, "%s: no inflight request\n", __func__);
p->status = USB_RET_STALL;
break;
}
} }
scsi_req_ref(req->req); scsi_req_ref(req->req);
req->data = p; req->data = p;

View File

@ -138,7 +138,7 @@ static void usb_mouse_event(void *opaque,
s->dz += dz1; s->dz += dz1;
s->buttons_state = buttons_state; s->buttons_state = buttons_state;
s->changed = 1; s->changed = 1;
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
static void usb_wacom_event(void *opaque, static void usb_wacom_event(void *opaque,
@ -152,7 +152,7 @@ static void usb_wacom_event(void *opaque,
s->dz += dz; s->dz += dz;
s->buttons_state = buttons_state; s->buttons_state = buttons_state;
s->changed = 1; s->changed = 1;
usb_wakeup(s->intr); usb_wakeup(s->intr, 0);
} }
static inline int int_clamp(int val, int vmin, int vmax) static inline int int_clamp(int val, int vmin, int vmax)

View File

@ -874,7 +874,8 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
return 0; return 0;
} }
static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
unsigned int stream)
{ {
EHCIState *s = container_of(bus, EHCIState, bus); EHCIState *s = container_of(bus, EHCIState, bus);
uint32_t portsc = s->portsc[ep->dev->port->index]; uint32_t portsc = s->portsc[ep->dev->port->index];
@ -1420,7 +1421,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
} }
spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0); spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr, spd, usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd,
(p->qtd.token & QTD_TOKEN_IOC) != 0); (p->qtd.token & QTD_TOKEN_IOC) != 0);
usb_packet_map(&p->packet, &p->sgl); usb_packet_map(&p->packet, &p->sgl);
p->async = EHCI_ASYNC_INITIALIZED; p->async = EHCI_ASYNC_INITIALIZED;
@ -1493,7 +1494,7 @@ static int ehci_process_itd(EHCIState *ehci,
dev = ehci_find_device(ehci, devaddr); dev = ehci_find_device(ehci, devaddr);
ep = usb_ep_get(dev, pid, endp); ep = usb_ep_get(dev, pid, endp);
if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) { if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
usb_packet_setup(&ehci->ipacket, pid, ep, addr, false, usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
(itd->transact[i] & ITD_XACT_IOC) != 0); (itd->transact[i] & ITD_XACT_IOC) != 0);
usb_packet_map(&ehci->ipacket, &ehci->isgl); usb_packet_map(&ehci->ipacket, &ehci->isgl);
usb_handle_packet(dev, &ehci->ipacket); usb_handle_packet(dev, &ehci->ipacket);

View File

@ -625,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
/* A wild guess on the FADDR semantics... */ /* A wild guess on the FADDR semantics... */
dev = usb_find_device(&s->port, ep->faddr[idx]); dev = usb_find_device(&s->port, ep->faddr[idx]);
uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf); uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
usb_packet_setup(&ep->packey[dir].p, pid, uep, usb_packet_setup(&ep->packey[dir].p, pid, uep, 0,
(dev->addr << 16) | (uep->nr << 8) | pid, false, true); (dev->addr << 16) | (uep->nr << 8) | pid, false, true);
usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len); usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep; ep->packey[dir].ep = ep;

View File

@ -830,7 +830,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
OHCI_BM(iso_td.flags, TD_DI) == 0; OHCI_BM(iso_td.flags, TD_DI) == 0;
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
usb_packet_setup(&ohci->usb_packet, pid, ep, addr, false, int_req); usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
usb_handle_packet(dev, &ohci->usb_packet); usb_handle_packet(dev, &ohci->usb_packet);
if (ohci->usb_packet.status == USB_RET_ASYNC) { if (ohci->usb_packet.status == USB_RET_ASYNC) {
@ -1034,7 +1034,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
} }
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r, usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
OHCI_BM(td.flags, TD_DI) == 0); OHCI_BM(td.flags, TD_DI) == 0);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
usb_handle_packet(dev, &ohci->usb_packet); usb_handle_packet(dev, &ohci->usb_packet);

View File

@ -879,7 +879,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
max_len = ((td->token >> 21) + 1) & 0x7ff; max_len = ((td->token >> 21) + 1) & 0x7ff;
spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0); spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd, usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
(td->ctrl & TD_CTRL_IOC) != 0); (td->ctrl & TD_CTRL_IOC) != 0);
qemu_sglist_add(&async->sgl, td->buffer, max_len); qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl); usb_packet_map(&async->packet, &async->sgl);

View File

@ -34,8 +34,8 @@
#else #else
#define DPRINTF(...) do {} while (0) #define DPRINTF(...) do {} while (0)
#endif #endif
#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ #define FIXME(_msg) do { fprintf(stderr, "FIXME %s:%d %s\n", \
__func__, __LINE__); abort(); } while (0) __func__, __LINE__, _msg); abort(); } while (0)
#define MAXPORTS_2 15 #define MAXPORTS_2 15
#define MAXPORTS_3 15 #define MAXPORTS_3 15
@ -301,6 +301,8 @@ typedef enum TRBCCode {
#define SLOT_CONTEXT_ENTRIES_SHIFT 27 #define SLOT_CONTEXT_ENTRIES_SHIFT 27
typedef struct XHCIState XHCIState; typedef struct XHCIState XHCIState;
typedef struct XHCIStreamContext XHCIStreamContext;
typedef struct XHCIEPContext XHCIEPContext;
#define get_field(data, field) \ #define get_field(data, field) \
(((data) >> field##_SHIFT) & field##_MASK) (((data) >> field##_SHIFT) & field##_MASK)
@ -351,6 +353,7 @@ typedef struct XHCITransfer {
unsigned int iso_pkts; unsigned int iso_pkts;
unsigned int slotid; unsigned int slotid;
unsigned int epid; unsigned int epid;
unsigned int streamid;
bool in_xfer; bool in_xfer;
bool iso_xfer; bool iso_xfer;
@ -367,7 +370,14 @@ typedef struct XHCITransfer {
uint64_t mfindex_kick; uint64_t mfindex_kick;
} XHCITransfer; } XHCITransfer;
typedef struct XHCIEPContext { struct XHCIStreamContext {
dma_addr_t pctx;
unsigned int sct;
XHCIRing ring;
XHCIStreamContext *sstreams;
};
struct XHCIEPContext {
XHCIState *xhci; XHCIState *xhci;
unsigned int slotid; unsigned int slotid;
unsigned int epid; unsigned int epid;
@ -382,11 +392,17 @@ typedef struct XHCIEPContext {
unsigned int max_psize; unsigned int max_psize;
uint32_t state; uint32_t state;
/* streams */
unsigned int max_pstreams;
bool lsa;
unsigned int nr_pstreams;
XHCIStreamContext *pstreams;
/* iso xfer scheduling */ /* iso xfer scheduling */
unsigned int interval; unsigned int interval;
int64_t mfindex_last; int64_t mfindex_last;
QEMUTimer *kick_timer; QEMUTimer *kick_timer;
} XHCIEPContext; };
typedef struct XHCISlot { typedef struct XHCISlot {
bool enabled; bool enabled;
@ -482,7 +498,7 @@ enum xhci_flags {
}; };
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
unsigned int epid); unsigned int epid, unsigned int streamid);
static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
unsigned int epid); unsigned int epid);
static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v); static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
@ -1068,18 +1084,116 @@ static void xhci_stop(XHCIState *xhci)
xhci->crcr_low &= ~CRCR_CRR; xhci->crcr_low &= ~CRCR_CRR;
} }
static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count,
dma_addr_t base)
{
XHCIStreamContext *stctx;
unsigned int i;
stctx = g_new0(XHCIStreamContext, count);
for (i = 0; i < count; i++) {
stctx[i].pctx = base + i * 16;
stctx[i].sct = -1;
}
return stctx;
}
static void xhci_reset_streams(XHCIEPContext *epctx)
{
unsigned int i;
for (i = 0; i < epctx->nr_pstreams; i++) {
epctx->pstreams[i].sct = -1;
g_free(epctx->pstreams[i].sstreams);
}
}
static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
{
assert(epctx->pstreams == NULL);
epctx->nr_pstreams = 2 << epctx->max_pstreams;
epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
}
static void xhci_free_streams(XHCIEPContext *epctx)
{
int i;
assert(epctx->pstreams != NULL);
if (!epctx->lsa) {
for (i = 0; i < epctx->nr_pstreams; i++) {
g_free(epctx->pstreams[i].sstreams);
}
}
g_free(epctx->pstreams);
epctx->pstreams = NULL;
epctx->nr_pstreams = 0;
}
static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
unsigned int streamid,
uint32_t *cc_error)
{
XHCIStreamContext *sctx;
dma_addr_t base;
uint32_t ctx[2], sct;
assert(streamid != 0);
if (epctx->lsa) {
if (streamid >= epctx->nr_pstreams) {
*cc_error = CC_INVALID_STREAM_ID_ERROR;
return NULL;
}
sctx = epctx->pstreams + streamid;
} else {
FIXME("secondary streams not implemented yet");
}
if (sctx->sct == -1) {
xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx));
fprintf(stderr, "%s: init sctx #%d @ %lx: %08x %08x\n", __func__,
streamid, sctx->pctx, ctx[0], ctx[1]);
sct = (ctx[0] >> 1) & 0x07;
if (epctx->lsa && sct != 1) {
*cc_error = CC_INVALID_STREAM_TYPE_ERROR;
return NULL;
}
sctx->sct = sct;
base = xhci_addr64(ctx[0] & ~0xf, ctx[1]);
xhci_ring_init(epctx->xhci, &sctx->ring, base);
}
return sctx;
}
static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
uint32_t state) XHCIStreamContext *sctx, uint32_t state)
{ {
uint32_t ctx[5]; 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)); xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
ctx[0] &= ~EP_STATE_MASK; ctx[0] &= ~EP_STATE_MASK;
ctx[0] |= state; ctx[0] |= state;
ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
ctx[3] = (epctx->ring.dequeue >> 16) >> 16; /* update ring dequeue ptr */
DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n", if (epctx->nr_pstreams) {
epctx->pctx, state, ctx[3], ctx[2]); if (sctx != NULL) {
xhci_dma_read_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
ctx2[0] &= 0xe;
ctx2[0] |= sctx->ring.dequeue | sctx->ring.ccs;
ctx2[1] = (sctx->ring.dequeue >> 16) >> 16;
xhci_dma_write_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
}
} else {
ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
epctx->pctx, state, ctx[3], ctx[2]);
}
xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
epctx->state = state; epctx->state = state;
} }
@ -1087,7 +1201,7 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
static void xhci_ep_kick_timer(void *opaque) static void xhci_ep_kick_timer(void *opaque)
{ {
XHCIEPContext *epctx = opaque; XHCIEPContext *epctx = opaque;
xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid); xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0);
} }
static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
@ -1117,16 +1231,22 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
slot->eps[epid-1] = epctx; slot->eps[epid-1] = epctx;
dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]); dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
xhci_ring_init(xhci, &epctx->ring, dequeue);
epctx->ring.ccs = ctx[2] & 1;
epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK; epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type); DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
epctx->pctx = pctx; epctx->pctx = pctx;
epctx->max_psize = ctx[1]>>16; epctx->max_psize = ctx[1]>>16;
epctx->max_psize *= 1+((ctx[1]>>8)&0xff); epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
epctx->max_pstreams = (ctx[0] >> 10) & 0xf;
epctx->lsa = (ctx[0] >> 15) & 1;
DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n", DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
epid/2, epid%2, epctx->max_psize); epid/2, epid%2, epctx->max_psize);
if (epctx->max_pstreams) {
xhci_alloc_streams(epctx, dequeue);
} else {
xhci_ring_init(xhci, &epctx->ring, dequeue);
epctx->ring.ccs = ctx[2] & 1;
}
for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
usb_packet_init(&epctx->transfers[i].packet); usb_packet_init(&epctx->transfers[i].packet);
} }
@ -1227,7 +1347,11 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
epctx = slot->eps[epid-1]; epctx = slot->eps[epid-1];
xhci_set_ep_state(xhci, epctx, EP_DISABLED); if (epctx->nr_pstreams) {
xhci_free_streams(epctx);
}
xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED);
qemu_free_timer(epctx->kick_timer); qemu_free_timer(epctx->kick_timer);
g_free(epctx); g_free(epctx);
@ -1264,7 +1388,11 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
epctx = slot->eps[epid-1]; epctx = slot->eps[epid-1];
xhci_set_ep_state(xhci, epctx, EP_STOPPED); xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
if (epctx->nr_pstreams) {
xhci_reset_streams(epctx);
}
return CC_SUCCESS; return CC_SUCCESS;
} }
@ -1315,16 +1443,22 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
return CC_USB_TRANSACTION_ERROR; return CC_USB_TRANSACTION_ERROR;
} }
xhci_set_ep_state(xhci, epctx, EP_STOPPED); xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
if (epctx->nr_pstreams) {
xhci_reset_streams(epctx);
}
return CC_SUCCESS; return CC_SUCCESS;
} }
static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
unsigned int epid, uint64_t pdequeue) unsigned int epid, unsigned int streamid,
uint64_t pdequeue)
{ {
XHCISlot *slot; XHCISlot *slot;
XHCIEPContext *epctx; XHCIEPContext *epctx;
XHCIStreamContext *sctx;
dma_addr_t dequeue; dma_addr_t dequeue;
assert(slotid >= 1 && slotid <= xhci->numslots); assert(slotid >= 1 && slotid <= xhci->numslots);
@ -1334,7 +1468,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
return CC_TRB_ERROR; return CC_TRB_ERROR;
} }
trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue); trace_usb_xhci_ep_set_dequeue(slotid, epid, streamid, pdequeue);
dequeue = xhci_mask64(pdequeue); dequeue = xhci_mask64(pdequeue);
slot = &xhci->slots[slotid-1]; slot = &xhci->slots[slotid-1];
@ -1346,16 +1480,26 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
epctx = slot->eps[epid-1]; epctx = slot->eps[epid-1];
if (epctx->state != EP_STOPPED) { if (epctx->state != EP_STOPPED) {
fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid); fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
return CC_CONTEXT_STATE_ERROR; return CC_CONTEXT_STATE_ERROR;
} }
xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF); if (epctx->nr_pstreams) {
epctx->ring.ccs = dequeue & 1; uint32_t err;
sctx = xhci_find_stream(epctx, streamid, &err);
if (sctx == NULL) {
return err;
}
xhci_ring_init(xhci, &sctx->ring, dequeue & ~0xf);
sctx->ring.ccs = dequeue & 1;
} else {
sctx = NULL;
xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
epctx->ring.ccs = dequeue & 1;
}
xhci_set_ep_state(xhci, epctx, EP_STOPPED); xhci_set_ep_state(xhci, epctx, sctx, EP_STOPPED);
return CC_SUCCESS; return CC_SUCCESS;
} }
@ -1484,12 +1628,22 @@ static void xhci_stall_ep(XHCITransfer *xfer)
XHCIState *xhci = xfer->xhci; XHCIState *xhci = xfer->xhci;
XHCISlot *slot = &xhci->slots[xfer->slotid-1]; XHCISlot *slot = &xhci->slots[xfer->slotid-1];
XHCIEPContext *epctx = slot->eps[xfer->epid-1]; XHCIEPContext *epctx = slot->eps[xfer->epid-1];
uint32_t err;
XHCIStreamContext *sctx;
epctx->ring.dequeue = xfer->trbs[0].addr; if (epctx->nr_pstreams) {
epctx->ring.ccs = xfer->trbs[0].ccs; sctx = xhci_find_stream(epctx, xfer->streamid, &err);
xhci_set_ep_state(xhci, epctx, EP_HALTED); if (sctx == NULL) {
DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid); return;
DPRINTF("xhci: will continue at "DMA_ADDR_FMT"\n", epctx->ring.dequeue); }
sctx->ring.dequeue = xfer->trbs[0].addr;
sctx->ring.ccs = xfer->trbs[0].ccs;
xhci_set_ep_state(xhci, epctx, sctx, EP_HALTED);
} else {
epctx->ring.dequeue = xfer->trbs[0].addr;
epctx->ring.ccs = xfer->trbs[0].ccs;
xhci_set_ep_state(xhci, epctx, NULL, EP_HALTED);
}
} }
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
@ -1518,8 +1672,8 @@ static int xhci_setup_packet(XHCITransfer *xfer)
} }
xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */ xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false, usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid,
xfer->int_req); xfer->trbs[0].addr, false, xfer->int_req);
usb_packet_map(&xfer->packet, &xfer->sgl); usb_packet_map(&xfer->packet, &xfer->sgl);
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
xfer->packet.pid, dev->addr, ep->nr); xfer->packet.pid, dev->addr, ep->nr);
@ -1572,7 +1726,7 @@ static int xhci_complete_packet(XHCITransfer *xfer)
default: default:
fprintf(stderr, "%s: FIXME: status = %d\n", __func__, fprintf(stderr, "%s: FIXME: status = %d\n", __func__,
xfer->packet.status); xfer->packet.status);
FIXME(); FIXME("unhandled USB_RET_*");
} }
return 0; return 0;
} }
@ -1585,7 +1739,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
trb_setup = &xfer->trbs[0]; trb_setup = &xfer->trbs[0];
trb_status = &xfer->trbs[xfer->trb_count-1]; trb_status = &xfer->trbs[xfer->trb_count-1];
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
/* at most one Event Data TRB allowed after STATUS */ /* at most one Event Data TRB allowed after STATUS */
if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
@ -1627,7 +1781,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
xhci_complete_packet(xfer); xhci_complete_packet(xfer);
if (!xfer->running_async && !xfer->running_retry) { if (!xfer->running_async && !xfer->running_retry) {
xhci_kick_ep(xhci, xfer->slotid, xfer->epid); xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0);
} }
return 0; return 0;
} }
@ -1710,26 +1864,29 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
xhci_complete_packet(xfer); xhci_complete_packet(xfer);
if (!xfer->running_async && !xfer->running_retry) { if (!xfer->running_async && !xfer->running_retry) {
xhci_kick_ep(xhci, xfer->slotid, xfer->epid); xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid);
} }
return 0; return 0;
} }
static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
{ {
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
return xhci_submit(xhci, xfer, epctx); return xhci_submit(xhci, xfer, epctx);
} }
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
unsigned int epid, unsigned int streamid)
{ {
XHCIStreamContext *stctx;
XHCIEPContext *epctx; XHCIEPContext *epctx;
XHCIRing *ring;
USBEndpoint *ep = NULL; USBEndpoint *ep = NULL;
uint64_t mfindex; uint64_t mfindex;
int length; int length;
int i; int i;
trace_usb_xhci_ep_kick(slotid, epid); trace_usb_xhci_ep_kick(slotid, epid, streamid);
assert(slotid >= 1 && slotid <= xhci->numslots); assert(slotid >= 1 && slotid <= xhci->numslots);
assert(epid >= 1 && epid <= 31); assert(epid >= 1 && epid <= 31);
@ -1782,14 +1939,28 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
return; return;
} }
xhci_set_ep_state(xhci, epctx, EP_RUNNING);
if (epctx->nr_pstreams) {
uint32_t err;
stctx = xhci_find_stream(epctx, streamid, &err);
if (stctx == NULL) {
return;
}
ring = &stctx->ring;
xhci_set_ep_state(xhci, epctx, stctx, EP_RUNNING);
} else {
ring = &epctx->ring;
streamid = 0;
xhci_set_ep_state(xhci, epctx, NULL, EP_RUNNING);
}
assert(ring->base != 0);
while (1) { while (1) {
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
if (xfer->running_async || xfer->running_retry) { if (xfer->running_async || xfer->running_retry) {
break; break;
} }
length = xhci_ring_chain_length(xhci, &epctx->ring); length = xhci_ring_chain_length(xhci, ring);
if (length < 0) { if (length < 0) {
break; break;
} else if (length == 0) { } else if (length == 0) {
@ -1808,11 +1979,12 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
xfer->trb_count = length; xfer->trb_count = length;
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL)); assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL));
} }
xfer->xhci = xhci; xfer->xhci = xhci;
xfer->epid = epid; xfer->epid = epid;
xfer->slotid = slotid; xfer->slotid = slotid;
xfer->streamid = streamid;
if (epid == 1) { if (epid == 1) {
if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) { if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
@ -1977,7 +2149,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: device address is %d\n", slot->devaddr); DPRINTF("xhci: device address is %d\n", slot->devaddr);
usb_device_reset(dev); usb_device_reset(dev);
usb_packet_setup(&p, USB_TOKEN_OUT, usb_packet_setup(&p, USB_TOKEN_OUT,
usb_ep_get(dev, USB_TOKEN_OUT, 0), usb_ep_get(dev, USB_TOKEN_OUT, 0), 0,
0, false, false); 0, false, false);
usb_device_handle_control(dev, &p, usb_device_handle_control(dev, &p,
DeviceOutRequest | USB_REQ_SET_ADDRESS, DeviceOutRequest | USB_REQ_SET_ADDRESS,
@ -2357,11 +2529,14 @@ static void xhci_process_commands(XHCIState *xhci)
} }
break; break;
case CR_SET_TR_DEQUEUE: case CR_SET_TR_DEQUEUE:
fprintf(stderr, "%s: CR_SET_TR_DEQUEUE\n", __func__);
slotid = xhci_get_slot(xhci, &event, &trb); slotid = xhci_get_slot(xhci, &event, &trb);
if (slotid) { if (slotid) {
unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
& TRB_CR_EPID_MASK; & TRB_CR_EPID_MASK;
event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid, unsigned int streamid = (trb.status >> 16) & 0xffff;
event.ccode = xhci_set_ep_dequeue(xhci, slotid,
epid, streamid,
trb.parameter); trb.parameter);
} }
break; break;
@ -2554,9 +2729,9 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
break; break;
case 0x10: /* HCCPARAMS */ case 0x10: /* HCCPARAMS */
if (sizeof(dma_addr_t) == 4) { if (sizeof(dma_addr_t) == 4) {
ret = 0x00081000; ret = 0x00087000;
} else { } else {
ret = 0x00081001; ret = 0x00087001;
} }
break; break;
case 0x14: /* DBOFF */ case 0x14: /* DBOFF */
@ -2880,6 +3055,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
uint64_t val, unsigned size) uint64_t val, unsigned size)
{ {
XHCIState *xhci = ptr; XHCIState *xhci = ptr;
unsigned int epid, streamid;
trace_usb_xhci_doorbell_write(reg, val); trace_usb_xhci_doorbell_write(reg, val);
@ -2898,13 +3074,15 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
(uint32_t)val); (uint32_t)val);
} }
} else { } else {
epid = val & 0xff;
streamid = (val >> 16) & 0xffff;
if (reg > xhci->numslots) { if (reg > xhci->numslots) {
fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg); fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg);
} else if (val > 31) { } else if (epid > 31) {
fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n",
(int)reg, (uint32_t)val); (int)reg, (uint32_t)val);
} else { } else {
xhci_kick_ep(xhci, reg, val); xhci_kick_ep(xhci, reg, epid, streamid);
} }
} }
} }
@ -2988,7 +3166,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet)
return; return;
} }
xhci_complete_packet(xfer); xhci_complete_packet(xfer);
xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid); xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid);
} }
static void xhci_child_detach(USBPort *uport, USBDevice *child) static void xhci_child_detach(USBPort *uport, USBDevice *child)
@ -3033,7 +3211,8 @@ static int xhci_find_epid(USBEndpoint *ep)
} }
} }
static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
unsigned int stream)
{ {
XHCIState *xhci = container_of(bus, XHCIState, bus); XHCIState *xhci = container_of(bus, XHCIState, bus);
int slotid; int slotid;
@ -3044,7 +3223,7 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr); DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
return; return;
} }
xhci_kick_ep(xhci, slotid, xhci_find_epid(ep)); xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream);
} }
static USBBusOps xhci_bus_ops = { static USBBusOps xhci_bus_ops = {

View File

@ -637,9 +637,3 @@ void usb_host_info(Monitor *mon, const QDict *qdict)
{ {
usb_host_scan(mon, usb_host_info_device); usb_host_scan(mon, usb_host_info_device);
} }
/* XXX add this */
int usb_host_device_close(const char *devname)
{
return 0;
}

144
hw/usb/host-legacy.c Normal file
View File

@ -0,0 +1,144 @@
/*
* Linux host USB redirector
*
* Copyright (c) 2005 Fabrice Bellard
*
* Copyright (c) 2008 Max Krasnyansky
* Support for host device auto connect & disconnect
* Major rewrite to support fully async operation
*
* Copyright 2008 TJ <linux@tjworld.net>
* Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
* to the legacy /proc/bus/usb USB device discovery and handling
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "hw/usb.h"
#include "hw/usb/host.h"
/*
* Autoconnect filter
* Format:
* auto:bus:dev[:vid:pid]
* auto:bus.dev[:vid:pid]
*
* bus - bus number (dec, * means any)
* dev - device number (dec, * means any)
* vid - vendor id (hex, * means any)
* pid - product id (hex, * means any)
*
* See 'lsusb' output.
*/
static int parse_filter(const char *spec, struct USBAutoFilter *f)
{
enum { BUS, DEV, VID, PID, DONE };
const char *p = spec;
int i;
f->bus_num = 0;
f->addr = 0;
f->vendor_id = 0;
f->product_id = 0;
for (i = BUS; i < DONE; i++) {
p = strpbrk(p, ":.");
if (!p) {
break;
}
p++;
if (*p == '*') {
continue;
}
switch (i) {
case BUS:
f->bus_num = strtol(p, NULL, 10);
break;
case DEV:
f->addr = strtol(p, NULL, 10);
break;
case VID:
f->vendor_id = strtol(p, NULL, 16);
break;
case PID:
f->product_id = strtol(p, NULL, 16);
break;
}
}
if (i < DEV) {
fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
return -1;
}
return 0;
}
USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
{
struct USBAutoFilter filter;
USBDevice *dev;
char *p;
dev = usb_create(bus, "usb-host");
if (strstr(devname, "auto:")) {
if (parse_filter(devname, &filter) < 0) {
goto fail;
}
} else {
p = strchr(devname, '.');
if (p) {
filter.bus_num = strtoul(devname, NULL, 0);
filter.addr = strtoul(p + 1, NULL, 0);
filter.vendor_id = 0;
filter.product_id = 0;
} else {
p = strchr(devname, ':');
if (p) {
filter.bus_num = 0;
filter.addr = 0;
filter.vendor_id = strtoul(devname, NULL, 16);
filter.product_id = strtoul(p + 1, NULL, 16);
} else {
goto fail;
}
}
}
qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
qdev_init_nofail(&dev->qdev);
return dev;
fail:
qdev_free(&dev->qdev);
return NULL;
}
static void usb_host_register_types(void)
{
usb_legacy_register("usb-host", "host", usb_host_device_open);
}
type_init(usb_host_register_types)

View File

@ -43,6 +43,7 @@
#include <linux/version.h> #include <linux/version.h>
#include "hw/usb.h" #include "hw/usb.h"
#include "hw/usb/desc.h" #include "hw/usb/desc.h"
#include "hw/usb/host.h"
/* We redefine it to avoid version problems */ /* We redefine it to avoid version problems */
struct usb_ctrltransfer { struct usb_ctrltransfer {
@ -87,14 +88,6 @@ struct endp_data {
int inflight; int inflight;
}; };
struct USBAutoFilter {
uint32_t bus_num;
uint32_t addr;
char *port;
uint32_t vendor_id;
uint32_t product_id;
};
enum USBHostDeviceOptions { enum USBHostDeviceOptions {
USB_HOST_OPT_PIPELINE, USB_HOST_OPT_PIPELINE,
}; };
@ -131,7 +124,6 @@ typedef struct USBHostDevice {
static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs); static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
static int usb_host_close(USBHostDevice *dev); static int usb_host_close(USBHostDevice *dev);
static int parse_filter(const char *spec, struct USBAutoFilter *f);
static void usb_host_auto_check(void *unused); static void usb_host_auto_check(void *unused);
static int usb_host_read_file(char *line, size_t line_size, static int usb_host_read_file(char *line, size_t line_size,
const char *device_file, const char *device_name); const char *device_file, const char *device_name);
@ -1544,75 +1536,10 @@ static const TypeInfo usb_host_dev_info = {
static void usb_host_register_types(void) static void usb_host_register_types(void)
{ {
type_register_static(&usb_host_dev_info); type_register_static(&usb_host_dev_info);
usb_legacy_register("usb-host", "host", usb_host_device_open);
} }
type_init(usb_host_register_types) type_init(usb_host_register_types)
USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
{
struct USBAutoFilter filter;
USBDevice *dev;
char *p;
dev = usb_create(bus, "usb-host");
if (strstr(devname, "auto:")) {
if (parse_filter(devname, &filter) < 0) {
goto fail;
}
} else {
if ((p = strchr(devname, '.'))) {
filter.bus_num = strtoul(devname, NULL, 0);
filter.addr = strtoul(p + 1, NULL, 0);
filter.vendor_id = 0;
filter.product_id = 0;
} else if ((p = strchr(devname, ':'))) {
filter.bus_num = 0;
filter.addr = 0;
filter.vendor_id = strtoul(devname, NULL, 16);
filter.product_id = strtoul(p + 1, NULL, 16);
} else {
goto fail;
}
}
qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
qdev_init_nofail(&dev->qdev);
return dev;
fail:
qdev_free(&dev->qdev);
return NULL;
}
int usb_host_device_close(const char *devname)
{
#if 0
char product_name[PRODUCT_NAME_SZ];
int bus_num, addr;
USBHostDevice *s;
if (strstr(devname, "auto:")) {
return usb_host_auto_del(devname);
}
if (usb_host_find_device(&bus_num, &addr, product_name,
sizeof(product_name), devname) < 0) {
return -1;
}
s = hostdev_find(bus_num, addr);
if (s) {
usb_device_delete_addr(s->bus_num, s->dev.addr);
return 0;
}
#endif
return -1;
}
/* /*
* Read sys file-system device file * Read sys file-system device file
* *
@ -1840,56 +1767,6 @@ static void usb_host_auto_check(void *unused)
qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000); qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
} }
/*
* Autoconnect filter
* Format:
* auto:bus:dev[:vid:pid]
* auto:bus.dev[:vid:pid]
*
* bus - bus number (dec, * means any)
* dev - device number (dec, * means any)
* vid - vendor id (hex, * means any)
* pid - product id (hex, * means any)
*
* See 'lsusb' output.
*/
static int parse_filter(const char *spec, struct USBAutoFilter *f)
{
enum { BUS, DEV, VID, PID, DONE };
const char *p = spec;
int i;
f->bus_num = 0;
f->addr = 0;
f->vendor_id = 0;
f->product_id = 0;
for (i = BUS; i < DONE; i++) {
p = strpbrk(p, ":.");
if (!p) {
break;
}
p++;
if (*p == '*') {
continue;
}
switch(i) {
case BUS: f->bus_num = strtol(p, NULL, 10); break;
case DEV: f->addr = strtol(p, NULL, 10); break;
case VID: f->vendor_id = strtol(p, NULL, 16); break;
case PID: f->product_id = strtol(p, NULL, 16); break;
}
}
if (i < DEV) {
fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
return -1;
}
return 0;
}
/**********************/ /**********************/
/* USB host device info */ /* USB host device info */

View File

@ -45,8 +45,3 @@ USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
{ {
return NULL; return NULL;
} }
int usb_host_device_close(const char *devname)
{
return 0;
}

44
hw/usb/host.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Linux host USB redirector
*
* Copyright (c) 2005 Fabrice Bellard
*
* Copyright (c) 2008 Max Krasnyansky
* Support for host device auto connect & disconnect
* Major rewrite to support fully async operation
*
* Copyright 2008 TJ <linux@tjworld.net>
* Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
* to the legacy /proc/bus/usb USB device discovery and handling
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_USB_HOST_H
#define QEMU_USB_HOST_H
struct USBAutoFilter {
uint32_t bus_num;
uint32_t addr;
char *port;
uint32_t vendor_id;
uint32_t product_id;
};
#endif /* QEMU_USB_HOST_H */

View File

@ -737,7 +737,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
uint8_t ep) uint8_t ep)
{ {
struct usb_redir_bulk_packet_header bulk_packet; struct usb_redir_bulk_packet_header bulk_packet;
size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; size_t size = usb_packet_size(p);
const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
if (usbredir_already_in_flight(dev, p->id)) { if (usbredir_already_in_flight(dev, p->id)) {
@ -771,12 +771,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
&bulk_packet, NULL, 0); &bulk_packet, NULL, 0);
} else { } else {
uint8_t buf[size]; uint8_t buf[size];
if (p->combined) { usb_packet_copy(p, buf, size);
iov_to_buf(p->combined->iov.iov, p->combined->iov.niov,
0, buf, size);
} else {
usb_packet_copy(p, buf, size);
}
usbredir_log_data(dev, "bulk data out:", buf, size); usbredir_log_data(dev, "bulk data out:", buf, size);
usbredirparser_send_bulk_packet(dev->parser, p->id, usbredirparser_send_bulk_packet(dev->parser, p->id,
&bulk_packet, buf, size); &bulk_packet, buf, size);
@ -1830,7 +1825,7 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
p = usbredir_find_packet_by_id(dev, ep, id); p = usbredir_find_packet_by_id(dev, ep, id);
if (p) { if (p) {
size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; size_t size = usb_packet_size(p);
usbredir_handle_status(dev, p, bulk_packet->status); usbredir_handle_status(dev, p, bulk_packet->status);
if (data_len > 0) { if (data_len > 0) {
usbredir_log_data(dev, "bulk data in:", data, data_len); usbredir_log_data(dev, "bulk data in:", data, data_len);
@ -1840,12 +1835,7 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
p->status = USB_RET_BABBLE; p->status = USB_RET_BABBLE;
data_len = len = size; data_len = len = size;
} }
if (p->combined) { usb_packet_copy(p, data, data_len);
iov_from_buf(p->combined->iov.iov, p->combined->iov.niov,
0, data, data_len);
} else {
usb_packet_copy(p, data, data_len);
}
} }
p->actual_length = len; p->actual_length = len;
if (p->pid == USB_TOKEN_IN && p->ep->pipeline) { if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {

View File

@ -18,7 +18,7 @@ process_includes () {
f=$src f=$src
while [ -n "$f" ] ; do while [ -n "$f" ] ; do
f=`tr -d '\r' < $f | awk '/^include / {printf "'$src_dir'/%s", $2}'` f=`cat $f | tr -d '\r' | awk '/^include / {printf "'$src_dir'/%s ", $2}'`
[ $? = 0 ] || exit 1 [ $? = 0 ] || exit 1
all_includes="$all_includes $f" all_includes="$all_includes $f"
done done

View File

@ -370,11 +370,11 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d"
usb_xhci_slot_reset(uint32_t slotid) "slotid %d" usb_xhci_slot_reset(uint32_t slotid) "slotid %d"
usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64 usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint32_t streamid, uint64_t param) "slotid %d, epid %d, streamid %d, ptr %016" PRIx64
usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" usb_xhci_ep_kick(uint32_t slotid, uint32_t epid, uint32_t streamid) "slotid %d, epid %d, streamid %d"
usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d" usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t streamid) "%p: slotid %d, epid %d, streamid %d"
usb_xhci_xfer_async(void *xfer) "%p" usb_xhci_xfer_async(void *xfer) "%p"
usb_xhci_xfer_nak(void *xfer) "%p" usb_xhci_xfer_nak(void *xfer) "%p"
usb_xhci_xfer_retry(void *xfer) "%p" usb_xhci_xfer_retry(void *xfer) "%p"

5
vl.c
View File

@ -1427,8 +1427,9 @@ static int usb_device_del(const char *devname)
int bus_num, addr; int bus_num, addr;
const char *p; const char *p;
if (strstart(devname, "host:", &p)) if (strstart(devname, "host:", &p)) {
return usb_host_device_close(p); return -1;
}
if (!usb_enabled(false)) { if (!usb_enabled(false)) {
return -1; return -1;