* USB EHCI patch for 0.14.0?
@ 2011-03-08 16:23 Erik Rull
2011-03-08 18:54 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: Erik Rull @ 2011-03-08 16:23 UTC (permalink / raw)
To: kvm@vger.kernel.org
Hi all,
I've found a usb ehci patch here in the mailing list (begin of january) but
it does not fit for 0.14.0.
Is there an updated patch for the latest qemu-kvm version?
Thanks a lot.
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-08 16:23 Erik Rull
@ 2011-03-08 18:54 ` David Ahern
2011-06-06 11:33 ` André Weidemann
0 siblings, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-03-08 18:54 UTC (permalink / raw)
To: Erik Rull; +Cc: kvm@vger.kernel.org
[-- Attachment #1: Type: text/plain, Size: 540 bytes --]
On 03/08/11 09:23, Erik Rull wrote:
> Hi all,
>
> I've found a usb ehci patch here in the mailing list (begin of january)
> but it does not fit for 0.14.0.
That was from me and prior work on ehci.
>
> Is there an updated patch for the latest qemu-kvm version?
Try the attached,
David
>
> Thanks a lot.
>
> Best regards,
>
> Erik
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
[-- Attachment #2: ehci-0.14.patch --]
[-- Type: text/plain, Size: 83559 bytes --]
diff --git a/Makefile.objs b/Makefile.objs
index 3ec7121..24ca955 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -192,7 +192,7 @@ hw-obj-$(CONFIG_PARALLEL) += parallel.o
#hw-obj-$(CONFIG_PCSPK) += pcspk.o
hw-obj-$(CONFIG_PCKBD) += pckbd.o
hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
-hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
+hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
hw-obj-$(CONFIG_FDC) += fdc.o
# needs fixes for cpu hotplug, so moved to Makefile.target:
# hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
diff --git a/Makefile.target b/Makefile.target
index 23367eb..27ac32a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -242,7 +242,7 @@ obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o
obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o
-obj-ia64-y += usb-uhci.o
+obj-ia64-y += usb-uhci.o usb-ehci.o
obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
# shared objects
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 3e0eddf..02f0389 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -10,6 +10,8 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y
CONFIG_PCSPK=y
CONFIG_PCKBD=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_EHCI=y
CONFIG_FDC=y
CONFIG_ACPI=y
CONFIG_APM=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 0471efb..22bd350 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -3,6 +3,7 @@ CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO=y
CONFIG_USB_UHCI=y
CONFIG_USB_OHCI=y
+CONFIG_USB_EHCI=y
CONFIG_NE2000_PCI=y
CONFIG_EEPRO100_PCI=y
CONFIG_PCNET_PCI=y
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index babfe21..2af9a0e 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -28,6 +28,7 @@
#include "pci.h"
#include "usb-uhci.h"
#include "usb-ohci.h"
+#include "usb-ehci.h"
#include "net.h"
#include "boards.h"
#include "ide.h"
@@ -178,8 +179,11 @@ static void pc_init1(ram_addr_t ram_size,
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
idebus[0], idebus[1], floppy_controller, rtc_state);
+ // TODO the piix3 does not have EHCI - looks like ICH4
+ // was first southbridge to support it.
if (pci_enabled && usb_enabled) {
usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+ usb_ehci_init(pci_bus, piix3_devfn + 3);
}
if (pci_enabled && acpi_enabled) {
@@ -189,7 +193,7 @@ static void pc_init1(ram_addr_t ram_size,
cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
/* TODO: Populate SPD eeprom data. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+ smbus = piix4_pm_init(pci_bus, piix3_devfn + 4, 0xb100,
isa_reserve_irq(9), *cmos_s3, *smi_irq,
kvm_enabled());
for (i = 0; i < 8; i++) {
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index ea3418c..d9457ed 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -100,6 +100,7 @@
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
+#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index abc7e61..15632c7 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -4,6 +4,13 @@
#include "sysemu.h"
#include "monitor.h"
+enum {
+ USB_VERSION_NONE,
+ USB_VERSION_1_1,
+ USB_VERSION_2_0,
+};
+
+
static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
static char *usb_get_dev_path(DeviceState *dev);
@@ -39,27 +46,51 @@ const VMStateDescription vmstate_usb_device = {
}
};
-void usb_bus_new(USBBus *bus, DeviceState *host)
+static void usb_bus_new(USBBus *bus, int version, DeviceState *host)
{
qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
bus->busnr = next_usb_bus++;
bus->qbus.allow_hotplug = 1; /* Yes, we can */
+ bus->version = version;
QTAILQ_INIT(&bus->free);
QTAILQ_INIT(&bus->used);
QTAILQ_INSERT_TAIL(&busses, bus, next);
}
-USBBus *usb_bus_find(int busnr)
+void usb_bus_new_v1(USBBus *bus, DeviceState *host)
+{
+ usb_bus_new(bus, USB_VERSION_1_1, host);
+}
+
+void usb_bus_new_v2(USBBus *bus, DeviceState *host)
+{
+ usb_bus_new(bus, USB_VERSION_2_0, host);
+}
+
+static USBBus *usb_bus_find(int busnr)
{
USBBus *bus;
- if (-1 == busnr)
- return QTAILQ_FIRST(&busses);
QTAILQ_FOREACH(bus, &busses, next) {
- if (bus->busnr == busnr)
- return bus;
+ if (bus->busnr == busnr) {
+ break;
+ }
}
- return NULL;
+
+ return bus;
+}
+
+/* device creation should be using this one */
+USBBus *usb_bus_find_version(int version)
+{
+ USBBus *bus;
+
+ QTAILQ_FOREACH(bus, &busses, next) {
+ if (bus->version == version) {
+ break;
+ }
+ }
+ return bus;
}
static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
@@ -106,20 +137,15 @@ void usb_qdev_register_many(USBDeviceInfo *info)
}
}
-USBDevice *usb_create(USBBus *bus, const char *name)
+static USBDevice *usb_create(USBBus *bus, const char *name)
{
DeviceState *dev;
-#if 1
- /* temporary stopgap until all usb is properly qdev-ified */
if (!bus) {
- bus = usb_bus_find(-1);
- if (!bus)
- return NULL;
- fprintf(stderr, "%s: no bus specified, using \"%s\" for \"%s\"\n",
- __FUNCTION__, bus->qbus.name, name);
+ fprintf(stderr, "%s: no bus specified for \"%s\"\n",
+ __FUNCTION__, name);
+ return NULL;
}
-#endif
dev = qdev_create(&bus->qbus, name);
return DO_UPCAST(USBDevice, qdev, dev);
@@ -127,7 +153,13 @@ USBDevice *usb_create(USBBus *bus, const char *name)
USBDevice *usb_create_simple(USBBus *bus, const char *name)
{
- USBDevice *dev = usb_create(bus, name);
+ USBDevice *dev;
+
+ /* if bus not given default to USB 1.1 */
+ if (!bus)
+ bus = usb_bus_find_version(USB_VERSION_1_1);
+
+ dev = usb_create(bus, name);
if (!dev) {
hw_error("Failed to create USB device '%s'\n", name);
}
@@ -135,6 +167,50 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
return dev;
}
+/* create USB device attached to USB 1.1 controller */
+USBDevice *usb_create_v1(const char *name)
+{
+ USBBus *bus = usb_bus_find_version(USB_VERSION_1_1);
+ return usb_create(bus, name);
+}
+
+/* create USB device attached to USB 2.0 controller */
+USBDevice *usb_create_v2(const char *name)
+{
+ USBBus *bus = usb_bus_find_version(USB_VERSION_2_0);
+ return usb_create(bus, name);
+}
+
+int usb_bus_migrate_v1(USBDevice *dev)
+{
+ USBBus *obus = usb_bus_from_device(dev);
+ BusState *bus_state;
+ int attached = dev->attached;
+ int rc = 0;
+
+ USBBus *nbus = usb_bus_find_version(USB_VERSION_1_1);
+ if (!nbus) {
+ return -1;
+ }
+
+ if (nbus == obus) {
+ return 0;
+ }
+
+ if (attached && (usb_device_detach(dev) != 0)) {
+ return -1;
+ }
+
+ bus_state = &nbus->qbus;
+ dev->qdev.parent_bus = bus_state;
+
+ if (attached) {
+ rc = usb_device_attach(dev);
+ }
+
+ return 0;
+}
+
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
USBPortOps *ops, int speedmask)
{
@@ -346,7 +422,6 @@ void usb_info(Monitor *mon)
/* handle legacy -usbdevice cmd line option */
USBDevice *usbdevice_create(const char *cmdline)
{
- USBBus *bus = usb_bus_find(-1 /* any */);
DeviceInfo *info;
USBDeviceInfo *usb;
char driver[32];
@@ -388,7 +463,7 @@ USBDevice *usbdevice_create(const char *cmdline)
error_report("usbdevice %s accepts no params", driver);
return NULL;
}
- return usb_create_simple(bus, usb->qdev.name);
+ return usb_create_simple(NULL, usb->qdev.name);
}
return usb->usbdevice_init(params);
}
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
new file mode 100644
index 0000000..92cbcac
--- /dev/null
+++ b/hw/usb-ehci.c
@@ -0,0 +1,2086 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * Copyright(c) 2008 Emutex Ltd. (address@hidden)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * TODO:
+ * o Downstream port handoff
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "pci.h"
+#include "usb-ehci.h"
+#include "monitor.h"
+
+#define EHCI_DEBUG 0
+#define STATE_DEBUG 0 /* state transitions */
+
+#if EHCI_DEBUG || STATE_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+#if STATE_DEBUG
+#define DPRINTF_ST DPRINTF
+#else
+#define DPRINTF_ST(...)
+#endif
+
+/* internal processing - reset HC to try and recover */
+#define USB_RET_PROCERR (-99)
+
+#define MMIO_SIZE 0x1000
+
+/* Capability Registers Base Address - section 2.2 */
+#define CAPREGBASE 0x0000
+#define CAPLENGTH CAPREGBASE + 0x0000 // 1-byte, 0x0001 reserved
+#define HCIVERSION CAPREGBASE + 0x0002 // 2-bytes, i/f version #
+#define HCSPARAMS CAPREGBASE + 0x0004 // 4-bytes, structural params
+#define HCCPARAMS CAPREGBASE + 0x0008 // 4-bytes, capability params
+#define EECP HCCPARAMS + 1
+#define HCSPPORTROUTE1 CAPREGBASE + 0x000c
+#define HCSPPORTROUTE2 CAPREGBASE + 0x0010
+
+#define OPREGBASE 0x0020 // Operational Registers Base Address
+
+#define USBCMD OPREGBASE + 0x0000
+#define USBCMD_RUNSTOP (1 << 0) // run / Stop
+#define USBCMD_HCRESET (1 << 1) // HC Reset
+#define USBCMD_FLS (3 << 2) // Frame List Size
+#define USBCMD_FLS_SH 2 // Frame List Size Shift
+#define USBCMD_PSE (1 << 4) // Periodic Schedule Enable
+#define USBCMD_ASE (1 << 5) // Asynch Schedule Enable
+#define USBCMD_IAAD (1 << 6) // Int Asynch Advance Doorbell
+#define USBCMD_LHCR (1 << 7) // Light Host Controller Reset
+#define USBCMD_ASPMC (3 << 8) // Async Sched Park Mode Count
+#define USBCMD_ASPME (1 << 11) // Async Sched Park Mode Enable
+#define USBCMD_ITC (0x7f << 16) // Int Threshold Control
+#define USBCMD_ITC_SH 16 // Int Threshold Control Shift
+
+#define USBSTS OPREGBASE + 0x0004
+#define USBSTS_RO_MASK 0x0000003f
+#define USBSTS_INT (1 << 0) // USB Interrupt
+#define USBSTS_ERRINT (1 << 1) // Error Interrupt
+#define USBSTS_PCD (1 << 2) // Port Change Detect
+#define USBSTS_FLR (1 << 3) // Frame List Rollover
+#define USBSTS_HSE (1 << 4) // Host System Error
+#define USBSTS_IAA (1 << 5) // Interrupt on Async Advance
+#define USBSTS_HALT (1 << 12) // HC Halted
+#define USBSTS_REC (1 << 13) // Reclamation
+#define USBSTS_PSS (1 << 14) // Periodic Schedule Status
+#define USBSTS_ASS (1 << 15) // Asynchronous Schedule Status
+
+/*
+ * Interrupt enable bits correspond to the interrupt active bits in USBSTS
+ * so no need to redefine here.
+ */
+#define USBINTR OPREGBASE + 0x0008
+#define USBINTR_MASK 0x0000003f
+
+#define FRINDEX OPREGBASE + 0x000c
+#define CTRLDSSEGMENT OPREGBASE + 0x0010
+#define PERIODICLISTBASE OPREGBASE + 0x0014
+#define ASYNCLISTADDR OPREGBASE + 0x0018
+#define ASYNCLISTADDR_MASK 0xffffffe0
+
+#define CONFIGFLAG OPREGBASE + 0x0040
+
+#define PORTSC (OPREGBASE + 0x0044)
+#define PORTSC_BEGIN PORTSC
+#define PORTSC_END (PORTSC + 4 * NB_PORTS)
+/*
+ * Bits that are reserverd or are read-only are masked out of values
+ * written to us by software
+ */
+#define PORTSC_RO_MASK 0x007021c5
+#define PORTSC_RWC_MASK 0x0000002a
+#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
+#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
+#define PORTSC_WKCN_E (1 << 20) // Wake on Connect Enable
+#define PORTSC_PTC (15 << 16) // Port Test Control
+#define PORTSC_PTC_SH 16 // Port Test Control shift
+#define PORTSC_PIC (3 << 14) // Port Indicator Control
+#define PORTSC_PIC_SH 14 // Port Indicator Control Shift
+#define PORTSC_POWNER (1 << 13) // Port Owner
+#define PORTSC_PPOWER (1 << 12) // Port Power
+#define PORTSC_LINESTAT (3 << 10) // Port Line Status
+#define PORTSC_LINESTAT_SH 10 // Port Line Status Shift
+#define PORTSC_PRESET (1 << 8) // Port Reset
+#define PORTSC_SUSPEND (1 << 7) // Port Suspend
+#define PORTSC_FPRES (1 << 6) // Force Port Resume
+#define PORTSC_OCC (1 << 5) // Over Current Change
+#define PORTSC_OCA (1 << 4) // Over Current Active
+#define PORTSC_PEDC (1 << 3) // Port Enable/Disable Change
+#define PORTSC_PED (1 << 2) // Port Enable/Disable
+#define PORTSC_CSC (1 << 1) // Connect Status Change
+#define PORTSC_CONNECT (1 << 0) // Current Connect Status
+
+//#define EHCI_NOMICROFRAMES
+
+#ifdef EHCI_NOMICROFRAMES
+#define FRAME_TIMER_FREQ 1000
+#else
+#define FRAME_TIMER_FREQ 8000
+#endif
+#define FRAME_TIMER_USEC (1000000 / FRAME_TIMER_FREQ)
+
+#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
+#define NB_PORTS 4 // Number of downstream ports
+#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
+#define MAX_ITERATIONS 20 // Max number of QH before we break the loop
+#define MAX_QH 100 // Max allowable queue heads in a chain
+
+/* Internal periodic / asynchronous schedule state machine states
+ */
+typedef enum {
+ EST_INACTIVE = 1000,
+ EST_ACTIVE,
+ EST_EXECUTING,
+ EST_SLEEPING,
+ /* The following states are internal to the state machine function
+ */
+ EST_WAITLISTHEAD,
+ EST_FETCHENTRY,
+ EST_FETCHQH,
+ EST_FETCHITD,
+ EST_ADVANCEQUEUE,
+ EST_FETCHQTD,
+ EST_EXECUTE,
+ EST_WRITEBACK,
+ EST_HORIZONTALQH
+} EHCI_STATES;
+
+/* macros for accessing fields within next link pointer entry */
+#define NLPTR_GET(x) ((x) & 0xffffffe0)
+#define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
+#define NLPTR_TBIT(x) ((x) & 1) // 1=invalid, 0=valid
+
+/* link pointer types */
+#define NLPTR_TYPE_ITD 0 // isoc xfer descriptor
+#define NLPTR_TYPE_QH 1 // queue head
+#define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor
+#define NLPTR_TYPE_FSTN 3 // frame span traversal node
+
+
+/* EHCI spec version 1.0 Section 3.3
+ */
+typedef struct EHCIitd {
+ uint32_t next;
+
+ uint32_t transact[8];
+#define ITD_XACT_ACTIVE (1 << 31)
+#define ITD_XACT_DBERROR (1 << 30)
+#define ITD_XACT_BABBLE (1 << 29)
+#define ITD_XACT_XACTERR (1 << 28)
+#define ITD_XACT_LENGTH_MASK 0x0fff0000
+#define ITD_XACT_LENGTH_SH 16
+#define ITD_XACT_IOC (1 << 15)
+#define ITD_XACT_PGSEL_MASK 0x00007000
+#define ITD_XACT_PGSEL_SH 12
+#define ITD_XACT_OFFSET_MASK 0x00000fff
+
+ uint32_t bufptr[7];
+#define ITD_BUFPTR_MASK 0xfffff000
+#define ITD_BUFPTR_SH 12
+#define ITD_BUFPTR_EP_MASK 0x00000f00
+#define ITD_BUFPTR_EP_SH 8
+#define ITD_BUFPTR_DEVADDR_MASK 0x0000007f
+#define ITD_BUFPTR_DEVADDR_SH 0
+#define ITD_BUFPTR_DIRECTION (1 << 11)
+#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff
+#define ITD_BUFPTR_MAXPKT_SH 0
+#define ITD_BUFPTR_MULT_MASK 0x00000003
+} EHCIitd;
+
+/* EHCI spec version 1.0 Section 3.4
+ */
+typedef struct EHCIsitd {
+ uint32_t next; // Standard next link pointer
+ uint32_t epchar;
+#define SITD_EPCHAR_IO (1 << 31)
+#define SITD_EPCHAR_PORTNUM_MASK 0x7f000000
+#define SITD_EPCHAR_PORTNUM_SH 24
+#define SITD_EPCHAR_HUBADD_MASK 0x007f0000
+#define SITD_EPCHAR_HUBADDR_SH 16
+#define SITD_EPCHAR_EPNUM_MASK 0x00000f00
+#define SITD_EPCHAR_EPNUM_SH 8
+#define SITD_EPCHAR_DEVADDR_MASK 0x0000007f
+
+ uint32_t uframe;
+#define SITD_UFRAME_CMASK_MASK 0x0000ff00
+#define SITD_UFRAME_CMASK_SH 8
+#define SITD_UFRAME_SMASK_MASK 0x000000ff
+
+ uint32_t results;
+#define SITD_RESULTS_IOC (1 << 31)
+#define SITD_RESULTS_PGSEL (1 << 30)
+#define SITD_RESULTS_TBYTES_MASK 0x03ff0000
+#define SITD_RESULTS_TYBYTES_SH 16
+#define SITD_RESULTS_CPROGMASK_MASK 0x0000ff00
+#define SITD_RESULTS_CPROGMASK_SH 8
+#define SITD_RESULTS_ACTIVE (1 << 7)
+#define SITD_RESULTS_ERR (1 << 6)
+#define SITD_RESULTS_DBERR (1 << 5)
+#define SITD_RESULTS_BABBLE (1 << 4)
+#define SITD_RESULTS_XACTERR (1 << 3)
+#define SITD_RESULTS_MISSEDUF (1 << 2)
+#define SITD_RESULTS_SPLITXSTATE (1 << 1)
+
+ uint32_t bufptr[2];
+#define SITD_BUFPTR_MASK 0xfffff000
+#define SITD_BUFPTR_CURROFF_MASK 0x00000fff
+#define SITD_BUFPTR_TPOS_MASK 0x00000018
+#define SITD_BUFPTR_TPOS_SH 3
+#define SITD_BUFPTR_TCNT_MASK 0x00000007
+
+ uint32_t backptr; // Standard next link pointer
+} EHCIsitd;
+
+/* EHCI spec version 1.0 Section 3.5
+ */
+typedef struct EHCIqtd {
+ uint32_t next; // Standard next link pointer
+ uint32_t altnext; // Standard next link pointer
+ uint32_t token;
+#define QTD_TOKEN_DTOGGLE (1 << 31)
+#define QTD_TOKEN_TBYTES_MASK 0x7fff0000
+#define QTD_TOKEN_TBYTES_SH 16
+#define QTD_TOKEN_IOC (1 << 15)
+#define QTD_TOKEN_CPAGE_MASK 0x00007000
+#define QTD_TOKEN_CPAGE_SH 12
+#define QTD_TOKEN_CERR_MASK 0x00000c00
+#define QTD_TOKEN_CERR_SH 10
+#define QTD_TOKEN_PID_MASK 0x00000300
+#define QTD_TOKEN_PID_SH 8
+#define QTD_TOKEN_ACTIVE (1 << 7)
+#define QTD_TOKEN_HALT (1 << 6)
+#define QTD_TOKEN_DBERR (1 << 5)
+#define QTD_TOKEN_BABBLE (1 << 4)
+#define QTD_TOKEN_XACTERR (1 << 3)
+#define QTD_TOKEN_MISSEDUF (1 << 2)
+#define QTD_TOKEN_SPLITXSTATE (1 << 1)
+#define QTD_TOKEN_PING (1 << 0)
+
+ uint32_t bufptr[5]; // Standard buffer pointer
+#define QTD_BUFPTR_MASK 0xfffff000
+} EHCIqtd;
+
+/* EHCI spec version 1.0 Section 3.6
+ */
+typedef struct EHCIqh {
+ uint32_t next; // Standard next link pointer
+
+ /* endpoint characteristics */
+ uint32_t epchar;
+#define QH_EPCHAR_RL_MASK 0xf0000000
+#define QH_EPCHAR_RL_SH 28
+#define QH_EPCHAR_C (1 << 27)
+#define QH_EPCHAR_MPLEN_MASK 0x07FF0000
+#define QH_EPCHAR_MPLEN_SH 16
+#define QH_EPCHAR_H (1 << 15)
+#define QH_EPCHAR_DTC (1 << 14)
+#define QH_EPCHAR_EPS_MASK 0x00003000
+#define QH_EPCHAR_EPS_SH 12
+#define EHCI_QH_EPS_FULL 0
+#define EHCI_QH_EPS_LOW 1
+#define EHCI_QH_EPS_HIGH 2
+#define EHCI_QH_EPS_RESERVED 3
+
+#define QH_EPCHAR_EP_MASK 0x00000f00
+#define QH_EPCHAR_EP_SH 8
+#define QH_EPCHAR_I (1 << 7)
+#define QH_EPCHAR_DEVADDR_MASK 0x0000007f
+#define QH_EPCHAR_DEVADDR_SH 0
+
+ /* endpoint capabilities */
+ uint32_t epcap;
+#define QH_EPCAP_MULT_MASK 0xc0000000
+#define QH_EPCAP_MULT_SH 30
+#define QH_EPCAP_PORTNUM_MASK 0x3f800000
+#define QH_EPCAP_PORTNUM_SH 23
+#define QH_EPCAP_HUBADDR_MASK 0x007f0000
+#define QH_EPCAP_HUBADDR_SH 16
+#define QH_EPCAP_CMASK_MASK 0x0000ff00
+#define QH_EPCAP_CMASK_SH 8
+#define QH_EPCAP_SMASK_MASK 0x000000ff
+#define QH_EPCAP_SMASK_SH 0
+
+ uint32_t current_qtd; // Standard next link pointer
+ uint32_t next_qtd; // Standard next link pointer
+ uint32_t altnext_qtd;
+#define QH_ALTNEXT_NAKCNT_MASK 0x0000001e
+#define QH_ALTNEXT_NAKCNT_SH 1
+
+ uint32_t token; // Same as QTD token
+ uint32_t bufptr[5]; // Standard buffer pointer
+#define BUFPTR_CPROGMASK_MASK 0x000000ff
+#define BUFPTR_FRAMETAG_MASK 0x0000001f
+#define BUFPTR_SBYTES_MASK 0x00000fe0
+#define BUFPTR_SBYTES_SH 5
+} EHCIqh;
+
+/* EHCI spec version 1.0 Section 3.7
+ */
+typedef struct EHCIfstn {
+ uint32_t next; // Standard next link pointer
+ uint32_t backptr; // Standard next link pointer
+} EHCIfstn;
+
+typedef struct {
+ PCIDevice dev;
+ qemu_irq irq;
+ target_phys_addr_t mem_base;
+ int mem;
+ int num_ports;
+ /*
+ * EHCI spec version 1.0 Section 2.3
+ * Host Controller Operational Registers
+ */
+ union {
+ uint8_t mmio[MMIO_SIZE];
+ struct {
+ uint8_t cap[OPREGBASE];
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ uint32_t usbintr;
+ uint32_t frindex;
+ uint32_t ctrldssegment;
+ uint32_t periodiclistbase;
+ uint32_t asynclistaddr;
+ uint32_t notused[9];
+ uint32_t configflag;
+ uint32_t portsc[NB_PORTS];
+ };
+ };
+ /*
+ * Internal states, shadow registers, etc
+ */
+ uint32_t sofv;
+ QEMUTimer *frame_timer;
+ int attach_poll_counter;
+ int astate; // Current state in asynchronous schedule
+ int pstate; // Current state in periodic schedule
+ USBPort ports[NB_PORTS];
+ uint8_t buffer[BUFF_SIZE];
+
+ /* cached data from guest - needs to be flushed
+ * when guest removes an entry (doorbell, handshake sequence)
+ */
+ EHCIqh qh; // copy of current QH (being worked on)
+ uint32_t qhaddr; // address QH read from
+
+ EHCIqtd qtd; // copy of current QTD (being worked on)
+ uint32_t qtdaddr; // address QTD read from
+
+ uint32_t itdaddr; // current ITD
+
+ uint32_t fetch_addr; // which address to look at next
+
+ USBBus bus;
+ USBPacket usb_packet;
+ int async_port_in_progress;
+ int async_complete;
+ uint32_t tbytes;
+ int pid;
+ int exec_status;
+ int isoch_pause;
+ uint32_t last_run_usec;
+ uint32_t frame_end_usec;
+} EHCIState;
+
+#define SET_LAST_RUN_CLOCK(s) \
+ (s)->last_run_usec = qemu_get_clock(vm_clock) / 1000;
+
+/* nifty macros from Arnon's EHCI version */
+#define get_field(data, field) \
+ (((data) & field##_MASK) >> field##_SH)
+
+#define set_field(data, newval, field) do { \
+ uint32_t val = *data; \
+ val &= ~ field##_MASK; \
+ val |= ((newval) << field##_SH) & field##_MASK; \
+ *data = val; \
+ } while(0)
+
+
+#if EHCI_DEBUG
+static const char *addr2str(unsigned addr)
+{
+ const char *r = " unknown";
+
+ switch(addr) {
+ case CAPLENGTH:
+ r = " CAPLENGTH";
+ break;
+
+ case HCIVERSION:
+ r = "HCIVERSION";
+ break;
+
+ case HCSPARAMS:
+ r = " HCSPARAMS";
+ break;
+
+ case HCCPARAMS:
+ r = " HCCPARAMS";
+ break;
+
+ case USBCMD:
+ r = " COMMAND";
+ break;
+
+ case USBSTS:
+ r = " STATUS";
+ break;
+
+ case USBINTR:
+ r = " INTERRUPT";
+ break;
+
+ case FRINDEX:
+ r = " FRAME IDX";
+ break;
+
+ case PERIODICLISTBASE:
+ r = "P-LIST BASE";
+ break;
+
+ case ASYNCLISTADDR:
+ r = "A-LIST ADDR";
+ break;
+
+ case PORTSC_BEGIN ... PORTSC_END:
+ r = "PORT STATUS";
+ break;
+
+ case CONFIGFLAG:
+ r = "CONFIG FLAG";
+ break;
+ }
+
+ return r;
+}
+#endif
+
+
+static inline void ehci_set_interrupt(EHCIState *s, int intr)
+{
+ int level = 0;
+
+ // TODO honour interrupt threshold requests
+
+ s->usbsts |= intr;
+
+ if ((s->usbsts & USBINTR_MASK) & s->usbintr)
+ level = 1;
+
+ qemu_set_irq(s->irq, level);
+}
+
+/* Attach or detach a device on root hub */
+
+static void ehci_attach(USBPort *port)
+{
+ EHCIState *s = port->opaque;
+ uint32_t *portsc = &s->portsc[port->index];
+
+ DPRINTF("ehci_attach invoked for index %d, portsc 0x%x, desc %s\n",
+ port->index, *portsc, dev ? dev->product_desc : "undefined");
+
+ *portsc |= PORTSC_CONNECT;
+ *portsc |= PORTSC_CSC;
+
+ /*
+ * If a high speed device is attached then we own this port(indicated
+ * by zero in the PORTSC_POWNER bit field) so set the status bit
+ * and set an interrupt if enabled.
+ */
+ if ( !(*portsc & PORTSC_POWNER)) {
+ ehci_set_interrupt(s, USBSTS_PCD);
+ }
+}
+
+static void ehci_detach(USBPort *port)
+{
+ EHCIState *s = port->opaque;
+ uint32_t *portsc = &s->portsc[port->index];
+
+ *portsc &= ~PORTSC_CONNECT;
+ *portsc |= PORTSC_CSC;
+}
+
+/* 4.1 host controller initialization */
+static void ehci_reset(void *opaque)
+{
+ EHCIState *s = opaque;
+ uint8_t *pci_conf;
+ int i;
+
+ pci_conf = s->dev.config;
+
+ memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
+
+ s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
+ s->usbsts = USBSTS_HALT;
+
+ s->astate = EST_INACTIVE;
+ s->pstate = EST_INACTIVE;
+ s->async_port_in_progress = -1;
+ s->async_complete = 0;
+ s->isoch_pause = -1;
+ s->attach_poll_counter = 0;
+
+ for(i = 0; i < NB_PORTS; i++) {
+ s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
+
+ if (s->ports[i].dev)
+ usb_attach(&s->ports[i], s->ports[i].dev);
+ }
+}
+
+static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
+{
+ EHCIState *s = ptr;
+ uint32_t val;
+
+ val = s->mmio[addr];
+
+ return val;
+}
+
+static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr)
+{
+ EHCIState *s = ptr;
+ uint32_t val;
+
+ val = s->mmio[addr] | (s->mmio[addr+1] << 8);
+
+ return val;
+}
+
+static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
+{
+ EHCIState *s = ptr;
+ uint32_t val;
+
+ val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
+ (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
+
+ return val;
+}
+
+static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+ fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n");
+ exit(1);
+}
+
+static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+ fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n");
+ exit(1);
+}
+
+static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
+{
+ uint32_t *portsc = &s->portsc[port];
+ int rwc;
+ USBDevice *dev = s->ports[port].dev;
+
+ DPRINTF("port_status_write: "
+ "PORTSC (port %d) curr %08X new %08X rw-clear %08X rw %08X\n",
+ port, *portsc, val, (val & PORTSC_RWC_MASK), val & PORTSC_RO_MASK);
+
+ rwc = val & PORTSC_RWC_MASK;
+ val &= PORTSC_RO_MASK;
+
+ // handle_read_write_clear(&val, portsc, PORTSC_PEDC | PORTSC_CSC);
+
+ *portsc &= ~rwc;
+
+ if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
+ DPRINTF("port_status_write: USBTRAN Port %d reset begin\n", port);
+ }
+
+ if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
+ DPRINTF("port_status_write: USBTRAN Port %d reset done\n", port);
+ usb_attach(&s->ports[port], dev);
+
+ // TODO how to handle reset of ports with no device
+ if (dev)
+ usb_send_msg(dev, USB_MSG_RESET);
+
+ if (s->ports[port].dev) {
+ DPRINTF("port_status_write: "
+ "Device was connected before reset, clearing CSC bit\n");
+ *portsc &= ~PORTSC_CSC;
+ }
+
+ /* Table 2.16 Set the enable bit(and enable bit change) to indicate
+ * to SW that this port has a high speed device attached
+ *
+ * TODO - when to disable?
+ */
+ val |= PORTSC_PED;
+ val |= PORTSC_PEDC;
+ }
+
+ *portsc &= ~PORTSC_RO_MASK;
+ *portsc |= val;
+ DPRINTF("port_status_write: Port %d status set to 0x%08x\n", port, *portsc);
+}
+
+static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+ EHCIState *s = ptr;
+ int i;
+#if EHCI_DEBUG
+ const char *str;
+#endif
+
+ /* Only aligned reads are allowed on OHCI */
+ if (addr & 3) {
+ fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"
+ TARGET_FMT_plx "\n", addr);
+ return;
+ }
+
+ if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
+ handle_port_status_write(s, (addr-PORTSC)/4, val);
+ return;
+ }
+
+ if (addr < OPREGBASE) {
+ fprintf(stderr, "usb-ehci: write attempt to read-only register"
+ TARGET_FMT_plx "\n", addr);
+ return;
+ }
+
+
+ /* Do any register specific pre-write processing here. */
+#if EHCI_DEBUG
+ str = addr2str((unsigned) addr);
+#endif
+ switch(addr)
+ {
+ case USBCMD:
+ DPRINTF("ehci_mem_writel: USBCMD val=0x%08X, current cmd=0x%08X\n",
+ val, s->usbcmd);
+
+ if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
+ DPRINTF("ehci_mem_writel: %s run, clear halt\n", str);
+ qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
+ SET_LAST_RUN_CLOCK(s);
+ s->usbsts &= ~USBSTS_HALT;
+ }
+
+ if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) {
+ DPRINTF(" ** STOP **\n");
+ qemu_del_timer(s->frame_timer);
+ // TODO - should finish out some stuff before setting halt
+ s->usbsts |= USBSTS_HALT;
+ }
+
+ if (val & USBCMD_HCRESET) {
+ DPRINTF("ehci_mem_writel: %s run, resetting\n", str);
+ ehci_reset(s);
+ val &= ~USBCMD_HCRESET;
+ }
+
+ /* not supporting dynamic frame list size at the moment */
+ if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
+ fprintf(stderr, "attempt to set frame list size -- value %d\n",
+ val & USBCMD_FLS);
+ val &= ~USBCMD_FLS;
+ }
+#if EHCI_DEBUG
+ if ((val & USBCMD_PSE) && !(s->usbcmd & USBCMD_PSE)) {
+ DPRINTF("periodic scheduling enabled\n");
+ }
+ if (!(val & USBCMD_PSE) && (s->usbcmd & USBCMD_PSE)) {
+ DPRINTF("periodic scheduling disabled\n");
+ }
+ if ((val & USBCMD_ASE) && !(s->usbcmd & USBCMD_ASE)) {
+ DPRINTF("asynchronous scheduling enabled\n");
+ }
+ if (!(val & USBCMD_ASE) && (s->usbcmd & USBCMD_ASE)) {
+ DPRINTF("asynchronous scheduling disabled\n");
+ }
+ if ((val & USBCMD_IAAD) && !(s->usbcmd & USBCMD_IAAD)) {
+ DPRINTF("doorbell request received\n");
+ }
+ if ((val & USBCMD_LHCR) && !(s->usbcmd & USBCMD_LHCR)) {
+ DPRINTF("light host controller reset received\n");
+ }
+ if ((val & USBCMD_ITC) != (s->usbcmd & USBCMD_ITC)) {
+ DPRINTF("interrupt threshold control set to %x\n",
+ (val & USBCMD_ITC)>>USBCMD_ITC_SH);
+ }
+#endif
+ break;
+
+
+ case USBSTS:
+ val &= USBSTS_RO_MASK; // bits 6 thru 31 are RO
+ DPRINTF("ehci_mem_writel: %s RWC set to 0x%08X\n", str, val);
+
+ val = (s->usbsts &= ~val); // bits 0 thru 5 are R/WC
+
+ DPRINTF("ehci_mem_writel: %s updating interrupt condition\n", str);
+ ehci_set_interrupt(s, 0);
+ break;
+
+
+ case USBINTR:
+ val &= USBINTR_MASK;
+ DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
+ break;
+
+ case FRINDEX:
+ s->sofv = val >> 3;
+ DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
+ break;
+
+ case CONFIGFLAG:
+ DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
+ val &= 0x1;
+ if (val) {
+ for(i = 0; i < NB_PORTS; i++)
+ s->portsc[i] &= ~PORTSC_POWNER;
+ }
+ break;
+
+ case PERIODICLISTBASE:
+ if ((s->usbcmd & USBCMD_PSE) && (s->usbcmd & USBCMD_RUNSTOP)) {
+ fprintf(stderr,
+ "ehci: PERIODIC list base register set while periodic schedule\n"
+ " is enabled and HC is enabled\n");
+ }
+ DPRINTF("ehci_mem_writel: P-LIST BASE set to 0x%08X\n", val);
+ break;
+
+ case ASYNCLISTADDR:
+ if ((s->usbcmd & USBCMD_ASE) && (s->usbcmd & USBCMD_RUNSTOP)) {
+ fprintf(stderr,
+ "ehci: ASYNC list address register set while async schedule\n"
+ " is enabled and HC is enabled\n");
+ }
+ DPRINTF("ehci_mem_writel: A-LIST ADDR set to 0x%08X\n", val);
+ break;
+ }
+
+ *(uint32_t *)(&s->mmio[addr]) = val;
+}
+
+
+// TODO : Put in common header file, duplication from usb-ohci.c
+
+/* Get an array of dwords from main memory */
+static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
+{
+ int i;
+
+ for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+ cpu_physical_memory_rw(addr,(uint8_t *)buf, sizeof(*buf), 0);
+ *buf = le32_to_cpu(*buf);
+ }
+
+ return 1;
+}
+
+/* Put an array of dwords in to main memory */
+static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
+{
+ int i;
+
+ for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+ uint32_t tmp = cpu_to_le32(*buf);
+ cpu_physical_memory_rw(addr,(uint8_t *)&tmp, sizeof(tmp), 1);
+ }
+
+ return 1;
+}
+
+// 4.10.2
+
+static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
+{
+ int i;
+ int dtoggle;
+ int ping;
+ int eps;
+ int reload;
+
+ // remember values in fields to preserve in qh after overlay
+
+ dtoggle = qh->token & QTD_TOKEN_DTOGGLE;
+ ping = qh->token & QTD_TOKEN_PING;
+
+ DPRINTF("setting qh.current from %08X to 0x%08X\n", qh->current_qtd,
+ ehci->qtdaddr);
+ qh->current_qtd = ehci->qtdaddr;
+ qh->next_qtd = qtd->next;
+ qh->altnext_qtd = qtd->altnext;
+ qh->token = qtd->token;
+
+
+ eps = get_field(qh->epchar, QH_EPCHAR_EPS);
+ if (eps == EHCI_QH_EPS_HIGH) {
+ qh->token &= ~QTD_TOKEN_PING;
+ qh->token |= ping;
+ }
+
+ reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+
+ for (i = 0; i < 5; i++) {
+ qh->bufptr[i] = qtd->bufptr[i];
+ }
+
+ if (!(qh->epchar & QH_EPCHAR_DTC)) {
+ // preserve QH DT bit
+ qh->token &= ~QTD_TOKEN_DTOGGLE;
+ qh->token |= dtoggle;
+ }
+
+ qh->bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
+ qh->bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
+
+ put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+
+ return 0;
+}
+
+static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
+{
+ int bufpos = 0;
+ int cpage, offset;
+ uint32_t head;
+ uint32_t tail;
+
+
+ if (!bytes)
+ return 0;
+
+ cpage = get_field(qh->token, QTD_TOKEN_CPAGE);
+ if (cpage > 4) {
+ fprintf(stderr, "cpage out of range (%d)\n", cpage);
+ return USB_RET_PROCERR;
+ }
+
+ offset = qh->bufptr[0] & ~QTD_BUFPTR_MASK;
+ DPRINTF("ehci_buffer_rw: %sing %d bytes %08x cpage %d offset %d\n",
+ rw ? "writ" : "read", bytes, qh->bufptr[0], cpage, offset);
+
+ do {
+ /* start and end of this page */
+ head = qh->bufptr[cpage] & QTD_BUFPTR_MASK;
+ tail = head + ~QTD_BUFPTR_MASK + 1;
+ /* add offset into page */
+ head |= offset;
+
+ if (bytes <= (tail - head)) {
+ tail = head + bytes;
+ }
+
+ DPRINTF("DATA %s cpage:%d head:%08X tail:%08X target:%08X\n",
+ rw ? "WRITE" : "READ ", cpage, head, tail, bufpos);
+
+ cpu_physical_memory_rw(head, &buffer[bufpos], tail - head, rw);
+
+ bufpos += (tail - head);
+ bytes -= (tail - head);
+
+ if (bytes > 0) {
+ cpage++;
+ offset = 0;
+ }
+ } while (bytes > 0);
+
+ /* save cpage */
+ set_field(&qh->token, cpage, QTD_TOKEN_CPAGE);
+
+ /* save offset into cpage */
+ offset = tail - head;
+ qh->bufptr[0] &= ~QTD_BUFPTR_MASK;
+ qh->bufptr[0] |= offset;
+
+ return 0;
+}
+
+static void ehci_async_complete_packet(USBPacket *packet, void *opaque)
+{
+ EHCIState *ehci = opaque;
+
+ DPRINTF("Async packet complete\n");
+ ehci->async_complete = 1;
+ ehci->exec_status = packet->len;
+}
+
+static int ehci_execute_complete(EHCIState *ehci,
+ EHCIqh *qh,
+ int ret)
+{
+ int i, c_err, reload;
+
+ if (ret == USB_RET_ASYNC && !ehci->async_complete) {
+ DPRINTF("not done yet\n");
+ return ret;
+ }
+
+ ehci->async_complete = 0;
+ i = ehci->async_port_in_progress;
+ ehci->async_port_in_progress = -1;
+
+ DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
+ ehci->qhaddr, qh->next, ehci->qtdaddr, ret);
+
+ if (ret < 0) {
+err:
+ /* TO-DO: put this is in a function that can be invoked below as well */
+ c_err = get_field(qh->token, QTD_TOKEN_CERR);
+ c_err--;
+ set_field(&qh->token, c_err, QTD_TOKEN_CERR);
+
+ switch(ret) {
+ case USB_RET_NODEV:
+ fprintf(stderr, "USB no device\n");
+ break;
+ case USB_RET_STALL:
+ fprintf(stderr, "USB stall\n");
+ qh->token |= QTD_TOKEN_HALT;
+ break;
+ case USB_RET_NAK:
+ /* 4.10.3 */
+ reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ if ((ehci->pid == USB_TOKEN_IN) && reload) {
+ int nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+ nakcnt--;
+ set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+ } else if (!reload) {
+ return USB_RET_NAK;
+ }
+ break;
+ case USB_RET_BABBLE:
+ fprintf(stderr, "USB babble TODO\n");
+ qh->token |= QTD_TOKEN_BABBLE;
+ break;
+ default:
+ fprintf(stderr, "USB invalid response %d to handle\n", ret);
+ /* TO-DO: transaction error */
+ ret = USB_RET_PROCERR;
+ break;
+ }
+ } else {
+ // DPRINTF("Short packet condition\n");
+ // TODO check 4.12 for splits
+
+ if ((ret > ehci->tbytes) && (ehci->pid == USB_TOKEN_IN)) {
+ ret = USB_RET_BABBLE;
+ goto err;
+ }
+
+ if (ehci->tbytes && ehci->pid == USB_TOKEN_IN) {
+ if (ehci_buffer_rw(ehci->buffer, qh, ret, 1) != 0) {
+ return USB_RET_PROCERR;
+ }
+ ehci->tbytes -= ret;
+ } else {
+ ehci->tbytes = 0;
+ }
+
+ DPRINTF("updating tbytes to %d\n", ehci->tbytes);
+ set_field(&qh->token, ehci->tbytes, QTD_TOKEN_TBYTES);
+ }
+
+ qh->token ^= QTD_TOKEN_DTOGGLE;
+ qh->token &= ~QTD_TOKEN_ACTIVE;
+
+ if ((ret >= 0) && (qh->token & QTD_TOKEN_IOC)) {
+ // TODO should do this after writeback to memory
+ ehci_set_interrupt(ehci, USBSTS_INT);
+ }
+
+ return ret;
+}
+
+// 4.10.3
+
+static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
+{
+ USBPort *port;
+ USBDevice *dev;
+ int ret;
+ int i;
+ int endp;
+ int devadr;
+
+ if ( !(qh->token & QTD_TOKEN_ACTIVE)) {
+ fprintf(stderr, "Attempting to execute inactive QH\n");
+ return USB_RET_PROCERR;
+ }
+
+ ehci->tbytes = (qh->token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
+ if (ehci->tbytes > BUFF_SIZE) {
+ fprintf(stderr, "Request for more bytes than allowed\n");
+ return USB_RET_PROCERR;
+ }
+
+ ehci->pid = (qh->token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
+ switch(ehci->pid) {
+ case 0: ehci->pid = USB_TOKEN_OUT; break;
+ case 1: ehci->pid = USB_TOKEN_IN; break;
+ case 2: ehci->pid = USB_TOKEN_SETUP; break;
+ default: fprintf(stderr, "bad token\n"); break;
+ }
+
+ if ((ehci->tbytes && ehci->pid != USB_TOKEN_IN) &&
+ (ehci_buffer_rw(ehci->buffer, qh, ehci->tbytes, 0) != 0)) {
+ return USB_RET_PROCERR;
+ }
+
+ endp = get_field(qh->epchar, QH_EPCHAR_EP);
+ devadr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
+
+ ret = USB_RET_NODEV;
+
+ // TO-DO: associating device with ehci port
+ for(i = 0; i < NB_PORTS; i++) {
+ port = &ehci->ports[i];
+ dev = port->dev;
+
+ // TODO sometime we will also need to check if we are the port owner
+
+ if (!(ehci->portsc[i] &(PORTSC_CONNECT))) {
+ DPRINTF("Port %d, no exec, not connected(%08X)\n",
+ i, ehci->portsc[i]);
+ continue;
+ }
+
+ ehci->usb_packet.pid = ehci->pid;
+ ehci->usb_packet.devaddr = devadr;
+ ehci->usb_packet.devep = endp;
+ ehci->usb_packet.data = ehci->buffer;
+ ehci->usb_packet.len = ehci->tbytes;
+ ehci->usb_packet.complete_cb = ehci_async_complete_packet;
+ ehci->usb_packet.complete_opaque = ehci;
+
+ ret = dev->info->handle_packet(dev, &ehci->usb_packet);
+
+ DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
+ ehci->qhaddr, qh->next, ehci->qtdaddr, ehci->pid,
+ ehci->usb_packet.len, ehci->tbytes, endp, ret);
+
+ if (ret != USB_RET_NODEV)
+ break;
+ }
+
+ if (ret > BUFF_SIZE) {
+ fprintf(stderr, "ret from handle packet > BUFF_SIZE\n");
+ return USB_RET_PROCERR;
+ }
+
+ if (ret == USB_RET_ASYNC) {
+ ehci->async_port_in_progress = i;
+ ehci->async_complete = 0;
+ }
+
+ return ret;
+}
+
+/* 4.7.2
+ */
+
+static int ehci_process_itd(EHCIState *ehci,
+ EHCIitd *itd)
+{
+ USBPort *port;
+ USBDevice *dev;
+ int ret;
+ int i, j;
+ int ptr;
+ int pid;
+ int pg;
+ int len;
+ int dir;
+ int devadr;
+ int endp;
+ int maxpkt;
+
+ dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
+ devadr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
+ endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
+ maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+
+#ifdef EHCI_NOMICROFRAMES
+ for(i = 0; i < 8; i++) {
+#else
+ i =(ehci->frindex & 7);
+#endif
+
+ if (itd->transact[i] & ITD_XACT_ACTIVE) {
+ DPRINTF("ISOCHRONOUS active for frame %d, interval %d\n",
+ ehci->frindex >> 3, i);
+
+ pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
+ ptr = (itd->bufptr[pg] & ITD_BUFPTR_MASK) |
+ (itd->transact[i] & ITD_XACT_OFFSET_MASK);
+ len = get_field(itd->transact[i], ITD_XACT_LENGTH);
+
+ if (len > BUFF_SIZE) {
+ return USB_RET_PROCERR;
+ }
+
+ DPRINTF("ISOCH: buffer %08X len %d\n", ptr, len);
+
+ if (!dir) {
+ cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 0);
+ pid = USB_TOKEN_OUT;
+ } else
+ pid = USB_TOKEN_IN;
+
+ ret = USB_RET_NODEV;
+
+ for(j = 0; j < NB_PORTS; j++) {
+ port = &ehci->ports[j];
+ dev = port->dev;
+
+ // TODO sometime we will also need to check if we are the port owner
+
+ if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
+ DPRINTF("Port %d, no exec, not connected(%08X)\n",
+ j, ehci->portsc[j]);
+ continue;
+ }
+
+ ehci->usb_packet.pid = ehci->pid;
+ ehci->usb_packet.devaddr = devadr;
+ ehci->usb_packet.devep = endp;
+ ehci->usb_packet.data = ehci->buffer;
+ ehci->usb_packet.len = len;
+ ehci->usb_packet.complete_cb = ehci_async_complete_packet;
+ ehci->usb_packet.complete_opaque = ehci;
+
+ DPRINTF("calling dev->info->handle_packet\n");
+ ret = dev->info->handle_packet(dev, &ehci->usb_packet);
+
+ if (ret != USB_RET_NODEV)
+ break;
+ }
+
+ /* In isoch, there is no facility to indicate a NAK so let's
+ * instead just complete a zero-byte transaction. Setting
+ * DBERR seems too draconian.
+ */
+
+ if (ret == USB_RET_NAK) {
+ if (ehci->isoch_pause > 0) {
+ DPRINTF("ISOCH: received a NAK but paused so returning\n");
+ ehci->isoch_pause--;
+ return 0;
+ } else if (ehci->isoch_pause == -1) {
+ DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n");
+ // Pause frindex for up to 50 msec waiting for data from
+ // remote
+ ehci->isoch_pause = 50;
+ return 0;
+ } else {
+ DPRINTF("ISOCH: isoch pause timeout! return 0\n");
+ ret = 0;
+ }
+ } else {
+ DPRINTF("ISOCH: received ACK, clearing pause\n");
+ ehci->isoch_pause = -1;
+ }
+
+ if (ret >= 0) {
+ itd->transact[i] &= ~ITD_XACT_ACTIVE;
+
+ if (itd->transact[i] & ITD_XACT_IOC) {
+ // TODO should do this after writeback to memory
+ ehci_set_interrupt(ehci, USBSTS_INT);
+ }
+ }
+
+ if (ret >= 0 && dir) {
+ cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 1);
+
+ if (ret != len) {
+ DPRINTF("ISOCH IN expected %d, got %d\n",
+ len, ret);
+ set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+ }
+ }
+ }
+
+#ifdef EHCI_NOMICROFRAMES
+ }
+#endif
+ return 0;
+}
+
+/* This state is the entry point for asynchronous schedule
+ * processing. Entry here consitutes a EHCI start event state (4.8.5)
+ */
+static int ehci_state_waitlisthead(EHCIState *ehci, int async, int *state)
+{
+ EHCIqh *qh = &ehci->qh;
+ int i = 0;
+ int again = 0;
+ uint32_t entry = ehci->asynclistaddr;
+
+ /* set reclamation flag at start event (4.8.6) */
+ if (async) {
+ ehci->usbsts |= USBSTS_REC;
+ }
+
+ /* Find the head of the list (4.9.1.1) */
+ for(i = 0; i < MAX_QH; i++) {
+ get_dwords(NLPTR_GET(entry), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+
+ if (qh->epchar & QH_EPCHAR_H) {
+ DPRINTF_ST("WAITLISTHEAD: QH %08X is the HEAD of the list\n",
+ entry);
+ if (async)
+ entry |= (NLPTR_TYPE_QH << 1);
+
+ ehci->fetch_addr = entry;
+ *state = EST_FETCHENTRY;
+ again = 1;
+ goto out;
+ }
+
+ DPRINTF_ST("WAITLISTHEAD: QH %08X is NOT the HEAD of the list\n",
+ entry);
+ entry = qh->next;
+ if (entry == ehci->asynclistaddr) {
+ DPRINTF("WAITLISTHEAD: reached beginning of QH list\n");
+ break;
+ }
+ }
+
+ /* no head found for list. */
+
+ *state = EST_ACTIVE;
+
+out:
+ return again;
+}
+
+
+/* This state is the entry point for periodic schedule processing as
+ * well as being a continuation state for async processing.
+ */
+static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
+{
+ int again = 0;
+ uint32_t entry = ehci->fetch_addr;
+
+#if EHCI_DEBUG == 0
+ if (qemu_get_clock(vm_clock) / 1000 >= ehci->frame_end_usec) {
+ if (async) {
+ DPRINTF("FETCHENTRY: FRAME timer elapsed, exit state machine\n");
+ goto out;
+ } else {
+ DPRINTF("FETCHENTRY: WARNING "
+ "- frame timer elapsed during periodic\n");
+ }
+ }
+#endif
+ if (entry < 0x1000) {
+ DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
+ *state = EST_ACTIVE;
+ goto out;
+ }
+
+ /* section 4.8, only QH in async schedule */
+ if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
+ fprintf(stderr, "non queue head request in async schedule\n");
+ return -1;
+ }
+
+ switch (NLPTR_TYPE_GET(entry)) {
+ case NLPTR_TYPE_QH:
+ DPRINTF_ST("FETCHENTRY: entry %X is a Queue Head\n", entry);
+ *state = EST_FETCHQH;
+ ehci->qhaddr = entry;
+ again = 1;
+ break;
+
+ case NLPTR_TYPE_ITD:
+ DPRINTF_ST("FETCHENTRY: entry %X is an ITD\n", entry);
+ *state = EST_FETCHITD;
+ ehci->itdaddr = entry;
+ again = 1;
+ break;
+
+ default:
+ // TODO: handle siTD and FSTN types
+ fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
+ "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
+ return -1;
+ }
+
+out:
+ return again;
+}
+
+static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
+{
+ EHCIqh *qh = &ehci->qh;
+ int reload;
+ int again = 0;
+
+ get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+
+ if (async && (qh->epchar & QH_EPCHAR_H)) {
+
+ /* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
+ if (ehci->usbsts & USBSTS_REC) {
+ ehci->usbsts &= ~USBSTS_REC;
+ } else {
+ DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
+ " - done processing\n", ehci->qhaddr);
+ *state = EST_ACTIVE;
+ goto out;
+ }
+ }
+
+#if EHCI_DEBUG
+ if (ehci->qhaddr != qh->next) {
+ DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
+ ehci->qhaddr,
+ qh->epchar & QH_EPCHAR_H,
+ qh->token & QTD_TOKEN_HALT,
+ qh->token & QTD_TOKEN_ACTIVE,
+ qh->next);
+ }
+#endif
+
+ reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ if (reload) {
+ DPRINTF_ST("FETCHQH: reloading nakcnt to %d\n", reload);
+ set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+ }
+
+ if (qh->token & QTD_TOKEN_HALT) {
+ DPRINTF_ST("FETCHQH: QH Halted, go horizontal\n");
+ *state = EST_HORIZONTALQH;
+ again = 1;
+
+ } else if ((qh->token & QTD_TOKEN_ACTIVE) && (qh->current_qtd > 0x1000)) {
+ DPRINTF_ST("FETCHQH: Active, !Halt, execute - fetch qTD\n");
+ ehci->qtdaddr = qh->current_qtd;
+ *state = EST_FETCHQTD;
+ again = 1;
+
+ } else {
+ /* EHCI spec version 1.0 Section 4.10.2 */
+ DPRINTF_ST("FETCHQH: !Active, !Halt, advance queue\n");
+ *state = EST_ADVANCEQUEUE;
+ again = 1;
+ }
+
+out:
+ return again;
+}
+
+static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
+{
+ EHCIitd itd;
+
+ get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
+ sizeof(EHCIitd) >> 2);
+ DPRINTF_ST("FETCHITD: Fetched ITD at address %08X " "(next is %08X)\n",
+ ehci->itdaddr, itd.next);
+
+ if (ehci_process_itd(ehci, &itd) != 0)
+ return -1;
+
+ put_dwords(NLPTR_GET(ehci->itdaddr), (uint32_t *) &itd,
+ sizeof(EHCIitd) >> 2);
+ ehci->itdaddr = itd.next;
+ *state = EST_FETCHITD;
+
+ return 1;
+}
+
+/* Section 4.10.2 - paragraph 3 */
+static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
+{
+#if 0
+ /* TO-DO: 4.10.2 - paragraph 2
+ * if I-bit is set to 1 and QH is not active
+ * go to horizontal QH
+ */
+ if (I-bit set) {
+ *state = EST_HORIZONTALQH;
+ goto out;
+ }
+#endif
+
+ /*
+ * want data and alt-next qTD is valid
+ */
+ if (((ehci->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
+ (ehci->qh.altnext_qtd > 0x1000) &&
+ (NLPTR_TBIT(ehci->qh.altnext_qtd) == 0)) {
+ DPRINTF_ST("ADVQUEUE: goto alt next qTD. "
+ "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
+ ehci->qh.current_qtd, ehci->qh.altnext_qtd,
+ ehci->qh.next_qtd, ehci->qh.next);
+ ehci->qtdaddr = ehci->qh.altnext_qtd;
+ *state = EST_FETCHQTD;
+
+ /*
+ * next qTD is valid
+ */
+ } else if ((ehci->qh.next_qtd > 0x1000) &&
+ (NLPTR_TBIT(ehci->qh.next_qtd) == 0)) {
+ DPRINTF_ST("ADVQUEUE: next qTD. "
+ "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
+ ehci->qh.current_qtd, ehci->qh.altnext_qtd,
+ ehci->qh.next_qtd, ehci->qh.next);
+ ehci->qtdaddr = ehci->qh.next_qtd;
+ *state = EST_FETCHQTD;
+
+ /*
+ * no valid qTD, try next QH
+ */
+ } else {
+ DPRINTF_ST("ADVQUEUE: go to horizontal QH\n");
+ *state = EST_HORIZONTALQH;
+ }
+
+ return 1;
+}
+
+/* Section 4.10.2 - paragraph 4 */
+static int ehci_state_fetchqtd(EHCIState *ehci, int async, int *state)
+{
+ EHCIqtd *qtd = &ehci->qtd;
+ int again = 0;
+
+ get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd, sizeof(EHCIqtd) >> 2);
+
+ if (qtd->token & QTD_TOKEN_ACTIVE) {
+ *state = EST_EXECUTE;
+ again = 1;
+ } else {
+ *state = EST_HORIZONTALQH;
+ again = 1;
+ }
+
+ return again;
+}
+
+static int ehci_state_horizqh(EHCIState *ehci, int async, int *state)
+{
+ int again = 0;
+
+ if (ehci->fetch_addr != ehci->qh.next) {
+ ehci->fetch_addr = ehci->qh.next;
+ *state = EST_FETCHENTRY;
+ again = 1;
+ } else {
+ *state = EST_ACTIVE;
+ }
+
+ return again;
+}
+
+static int ehci_state_execute(EHCIState *ehci, int async, int *state)
+{
+ EHCIqh *qh = &ehci->qh;
+ EHCIqtd *qtd = &ehci->qtd;
+ int again = 0;
+ int reload, nakcnt;
+ int smask;
+
+ if (async) {
+ DPRINTF_ST(">>>>> ASYNC STATE MACHINE execute QH 0x%08x, QTD 0x%08x\n",
+ ehci->qhaddr, ehci->qtdaddr);
+ } else {
+ DPRINTF_ST(">>>>> PERIODIC STATE MACHINE execute\n");
+ }
+
+ if (ehci_qh_do_overlay(ehci, qh, qtd) != 0)
+ return -1;
+
+ smask = get_field(qh->epcap, QH_EPCAP_SMASK);
+#ifndef EHCI_NOMICROFRAMES
+ if (smask && (smask & (1 << (ehci->frindex & 7))) == 0) {
+ DPRINTF_ST("PERIODIC active not interval: mask %x, frindex %d,%d\n",
+ smask, (ehci->frindex >> 3),(ehci->frindex & 7));
+
+ *state = EST_HORIZONTALQH;
+ again = 1;
+ goto out;
+ }
+#endif
+
+ if (!smask) {
+ reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+ if (reload && !nakcnt) {
+ DPRINTF_ST("EXECUTE: RL != 0 but NakCnt == 0 -- no execute\n");
+ *state = EST_HORIZONTALQH;
+ again = 1;
+ goto out;
+ }
+ }
+
+ // TODO verify enough time remains in the uframe as in 4.4.1.1
+
+ // TODO write back ptr to async list when done or out of time
+
+ // TODO Windows does not seem to ever set the MULT field
+
+
+ if (!async)
+ {
+ int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+ if (!transactCtr) {
+ DPRINTF("ZERO transactctr for int qh, go HORIZ\n");
+ *state = EST_HORIZONTALQH;
+ again = 1;
+ goto out;
+ }
+ }
+
+
+ if (async)
+ ehci->usbsts |= USBSTS_REC;
+
+ ehci->exec_status = ehci_execute(ehci, qh);
+ if (ehci->exec_status == USB_RET_PROCERR) {
+ again = -1;
+ goto out;
+ }
+ *state = EST_EXECUTING;
+
+ if (ehci->exec_status != USB_RET_ASYNC)
+ again = 1;
+
+out:
+ return again;
+}
+
+static int ehci_state_executing(EHCIState *ehci, int async, int *state)
+{
+ EHCIqh *qh = &ehci->qh;
+ int again = 0;
+ int reload, nakcnt;
+
+ ehci->exec_status = ehci_execute_complete(ehci, qh, ehci->exec_status);
+ if (ehci->exec_status == USB_RET_ASYNC) {
+ goto out;
+ }
+ if (ehci->exec_status == USB_RET_PROCERR) {
+ again = -1;
+ goto out;
+ }
+
+ // 4.10.3
+ if (!async) {
+ int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+ transactCtr--;
+ set_field(&qh->epcap, transactCtr, QH_EPCAP_MULT);
+ // 4.10.3, bottom of page 82, should exit this state when transaction
+ // counter decrements to 0
+ }
+
+
+ reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ if (reload) {
+ nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+ if (ehci->exec_status == USB_RET_NAK) {
+ if (nakcnt) {
+ nakcnt--;
+ }
+ DPRINTF_ST("EXECUTING: Nak occured and RL != 0, dec NakCnt to %d\n",
+ nakcnt);
+ } else {
+ nakcnt = reload;
+ DPRINTF_ST("EXECUTING: Nak didn't occur, reloading to %d\n",
+ nakcnt);
+ }
+ set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+ }
+
+ /*
+ * Write the qh back to guest physical memory. This step isn't
+ * in the EHCI spec but we need to do it since we don't share
+ * physical memory with our guest VM.
+ */
+
+ DPRINTF("EXECUTING: write QH to VM memory: qhaddr 0x%x, next 0x%x\n",
+ ehci->qhaddr, qh->next);
+ put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+
+ /* 4.10.5 */
+ if ((ehci->exec_status == USB_RET_NAK) || (qh->token & QTD_TOKEN_ACTIVE)) {
+ *state = EST_HORIZONTALQH;
+ } else {
+ *state = EST_WRITEBACK;
+ }
+
+ again = 1;
+
+out:
+ return again;
+}
+
+
+static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
+{
+ EHCIqh *qh = &ehci->qh;
+ int again = 0;
+
+ /* Write back the QTD from the QH area */
+ DPRINTF_ST("WRITEBACK: write QTD to VM memory\n");
+ put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->next_qtd,
+ sizeof(EHCIqtd) >> 2);
+
+ /* TODO confirm next state. For now, keep going if async
+ * but stop after one qtd if periodic
+ */
+ //if (async) {
+ *state = EST_ADVANCEQUEUE;
+ again = 1;
+ //} else {
+ // *state = EST_ACTIVE;
+ //}
+ return again;
+}
+
+/*
+ * This is the state machine that is common to both async and periodic
+ */
+
+static int ehci_advance_state(EHCIState *ehci,
+ int async,
+ int state)
+{
+ int again;
+ int iter = 0;
+
+ do {
+ if (state == EST_FETCHQH) {
+ iter++;
+ /* if we are roaming a lot of QH without executing a qTD
+ * something is wrong with the linked list. TO-DO: why is
+ * this hack needed?
+ */
+ if (iter > MAX_ITERATIONS) {
+ DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");
+ state = EST_ACTIVE;
+ break;
+ }
+ }
+ switch(state) {
+ case EST_WAITLISTHEAD:
+ again = ehci_state_waitlisthead(ehci, async, &state);
+ break;
+
+ case EST_FETCHENTRY:
+ again = ehci_state_fetchentry(ehci, async, &state);
+ break;
+
+ case EST_FETCHQH:
+ again = ehci_state_fetchqh(ehci, async, &state);
+ break;
+
+ case EST_FETCHITD:
+ again = ehci_state_fetchitd(ehci, async, &state);
+ break;
+
+ case EST_ADVANCEQUEUE:
+ again = ehci_state_advqueue(ehci, async, &state);
+ break;
+
+ case EST_FETCHQTD:
+ again = ehci_state_fetchqtd(ehci, async, &state);
+ break;
+
+ case EST_HORIZONTALQH:
+ again = ehci_state_horizqh(ehci, async, &state);
+ break;
+
+ case EST_EXECUTE:
+ iter = 0;
+ again = ehci_state_execute(ehci, async, &state);
+ break;
+
+ case EST_EXECUTING:
+ again = ehci_state_executing(ehci, async, &state);
+ break;
+
+ case EST_WRITEBACK:
+ again = ehci_state_writeback(ehci, async, &state);
+ break;
+
+ default:
+ fprintf(stderr, "Bad state!\n");
+ again = -1;
+ break;
+ }
+
+ if (again < 0) {
+ fprintf(stderr, "processing error - resetting ehci HC\n");
+ ehci_reset(ehci);
+ again = 0;
+ }
+ }
+ while (again);
+
+ return state;
+}
+
+static void ehci_advance_async_state(EHCIState *ehci)
+{
+ EHCIqh qh;
+ int state = ehci->astate;
+
+ switch(state) {
+ case EST_INACTIVE:
+ if (!(ehci->usbcmd & USBCMD_ASE)) {
+ break;
+ }
+ ehci->usbsts |= USBSTS_ASS;
+ ehci->astate = EST_ACTIVE;
+ // No break, fall through to ACTIVE
+
+ case EST_ACTIVE:
+ if ( !(ehci->usbcmd & USBCMD_ASE)) {
+ ehci->usbsts &= ~USBSTS_ASS;
+ ehci->astate = EST_INACTIVE;
+ break;
+ }
+
+ /* If the doorbell is set, the guest wants to make a change to the
+ * schedule. The host controller needs to release cached data.
+ * (section 4.8.2)
+ */
+ if (ehci->usbcmd & USBCMD_IAAD) {
+ DPRINTF("ASYNC: doorbell request acknowledged\n");
+ ehci->usbcmd &= ~USBCMD_IAAD;
+ ehci_set_interrupt(ehci, USBSTS_IAA);
+ break;
+ }
+
+ /* make sure guest has acknowledged */
+ /* TO-DO: is this really needed? */
+ if (ehci->usbsts & USBSTS_IAA) {
+ DPRINTF("IAA status bit still set.\n");
+ break;
+ }
+
+ DPRINTF_ST("ASYNC: waiting for listhead, starting at %08x\n",
+ ehci->asynclistaddr);
+ /* check that address register has been set */
+ if (ehci->asynclistaddr == 0) {
+ break;
+ }
+
+ state = EST_WAITLISTHEAD;
+ /* fall through */
+
+ case EST_FETCHENTRY:
+ /* fall through */
+
+ case EST_EXECUTING:
+ get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) &qh,
+ sizeof(EHCIqh) >> 2);
+ ehci->astate = ehci_advance_state(ehci, 1, state);
+ break;
+
+ default:
+ /* this should only be due to a developer mistake */
+ fprintf(stderr, "ehci: Bad asynchronous state %d. "
+ "Resetting to active\n", ehci->astate);
+ ehci->astate = EST_ACTIVE;
+ }
+}
+
+static void ehci_advance_periodic_state(EHCIState *ehci)
+{
+ uint32_t entry;
+ uint32_t list;
+
+ // 4.6
+
+ switch(ehci->pstate) {
+ case EST_INACTIVE:
+ if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
+ DPRINTF("PERIODIC going active\n");
+ ehci->usbsts |= USBSTS_PSS;
+ ehci->pstate = EST_ACTIVE;
+ // No break, fall through to ACTIVE
+ } else
+ break;
+
+ case EST_ACTIVE:
+ if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
+ DPRINTF("PERIODIC going inactive\n");
+ ehci->usbsts &= ~USBSTS_PSS;
+ ehci->pstate = EST_INACTIVE;
+ break;
+ }
+
+ list = ehci->periodiclistbase & 0xfffff000;
+ /* check that register has been set */
+ if (list == 0) {
+ break;
+ }
+ list |= ((ehci->frindex & 0x1ff8) >> 1);
+
+ cpu_physical_memory_rw(list, (uint8_t *) &entry, sizeof entry, 0);
+ entry = le32_to_cpu(entry);
+
+ DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
+ ehci->frindex / 8, list, entry);
+ ehci->fetch_addr = entry;
+ ehci->pstate = ehci_advance_state(ehci, 0, EST_FETCHENTRY);
+ break;
+
+ case EST_EXECUTING:
+ DPRINTF("PERIODIC state adv for executing\n");
+ ehci->pstate = ehci_advance_state(ehci, 0, EST_EXECUTING);
+ break;
+
+ default:
+ /* this should only be due to a developer mistake */
+ fprintf(stderr, "ehci: Bad periodic state %d. "
+ "Resetting to active\n", ehci->pstate);
+ ehci->pstate = EST_ACTIVE;
+ }
+}
+
+static void ehci_frame_timer(void *opaque)
+{
+ EHCIState *ehci = opaque;
+ int64_t expire_time, t_now;
+ int usec_elapsed;
+ int frames;
+ int usec_now;
+ int i;
+ int skipped_frames = 0;
+
+
+ t_now = qemu_get_clock(vm_clock);
+ expire_time = t_now + (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+ if (expire_time == t_now)
+ expire_time++;
+
+ usec_now = t_now / 1000;
+ usec_elapsed = usec_now - ehci->last_run_usec;
+ frames = usec_elapsed / FRAME_TIMER_USEC;
+ ehci->frame_end_usec = usec_now + FRAME_TIMER_USEC - 10;
+
+ for(i = 0; i < frames; i++) {
+ if ( !(ehci->usbsts & USBSTS_HALT)) {
+ if (ehci->isoch_pause <= 0) {
+#ifdef EHCI_NOMICROFRAMES
+ ehci->frindex += 8;
+#else
+ ehci->frindex++;
+#endif
+ }
+
+ if (ehci->frindex > 0x00001fff) {
+ ehci->frindex = 0;
+ ehci_set_interrupt(ehci, USBSTS_FLR);
+ }
+
+ ehci->sofv = (ehci->frindex - 1) >> 3;
+ ehci->sofv &= 0x000003ff;
+ }
+
+ if (frames - i > 10)
+ skipped_frames++;
+ else {
+ // TODO could this cause periodic frames to get skipped if async
+ // active?
+ if (ehci->astate != EST_EXECUTING)
+ ehci_advance_periodic_state(ehci);
+ }
+
+ ehci->last_run_usec += FRAME_TIMER_USEC;
+ }
+
+#if 0
+ if (skipped_frames)
+ DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames);
+#endif
+
+ /* Async is not inside loop since it executes everything it can once
+ * called
+ */
+ if (ehci->pstate != EST_EXECUTING)
+ ehci_advance_async_state(ehci);
+
+ qemu_mod_timer(ehci->frame_timer, expire_time);
+}
+
+static CPUReadMemoryFunc *ehci_readfn[3]={
+ ehci_mem_readb,
+ ehci_mem_readw,
+ ehci_mem_readl
+};
+
+static CPUWriteMemoryFunc *ehci_writefn[3]={
+ ehci_mem_writeb,
+ ehci_mem_writew,
+ ehci_mem_writel
+};
+
+static void ehci_map(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ EHCIState *s =(EHCIState *)pci_dev;
+
+ DPRINTF("ehci_map: region %d, addr %08llX, size %lld, s->mem %08X\n",
+ region_num, addr, size, s->mem);
+ s->mem_base = addr;
+ cpu_register_physical_memory(addr, size, s->mem);
+}
+
+static int usb_ehci_initfn(PCIDevice *dev);
+
+static PCIDeviceInfo ehci_info[] = {
+ {
+ .qdev.name = "usb-ehci",
+ .qdev.size = sizeof(EHCIState),
+ .init = usb_ehci_initfn,
+ },{
+ /* end of list */
+ }
+};
+
+static USBPortOps ehci_port_ops = {
+ .attach = ehci_attach,
+ .detach = ehci_detach,
+ .wakeup = NULL,
+};
+
+static int usb_ehci_initfn(PCIDevice *dev)
+{
+ EHCIState *s = DO_UPCAST(EHCIState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+ int i;
+
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82801D);
+ pci_set_byte(&pci_conf[PCI_REVISION_ID], 0x10);
+ pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
+ pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
+ pci_set_byte(&pci_conf[PCI_HEADER_TYPE], PCI_HEADER_TYPE_NORMAL);
+
+ /* capabilities pointer */
+ pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
+ //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
+
+ pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); // interrupt pin 3
+ pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
+ pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
+
+ // pci_conf[0x50] = 0x01; // power management caps
+
+ pci_set_byte(&pci_conf[0x60], 0x20); // spec release number (2.1.4)
+ pci_set_byte(&pci_conf[0x61], 0x20); // frame length adjustment (2.1.5)
+ pci_set_word(&pci_conf[0x62], 0x00); // port wake up capability (2.1.6)
+
+ pci_conf[0x64] = 0x00;
+ pci_conf[0x65] = 0x00;
+ pci_conf[0x66] = 0x00;
+ pci_conf[0x67] = 0x00;
+ pci_conf[0x68] = 0x01;
+ pci_conf[0x69] = 0x00;
+ pci_conf[0x6a] = 0x00;
+ pci_conf[0x6b] = 0x00; // USBLEGSUP
+ pci_conf[0x6c] = 0x00;
+ pci_conf[0x6d] = 0x00;
+ pci_conf[0x6e] = 0x00;
+ pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
+
+ // 2.2 host controller interface version
+ s->mmio[0x00] = (uint8_t) OPREGBASE;
+ s->mmio[0x01] = 0x00;
+ s->mmio[0x02] = 0x00;
+ s->mmio[0x03] = 0x01; // HC version
+ s->mmio[0x04] = NB_PORTS; // Number of downstream ports
+ s->mmio[0x05] = 0x00; // No companion ports at present
+ s->mmio[0x06] = 0x00;
+ s->mmio[0x07] = 0x00;
+ s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable
+ s->mmio[0x09] = 0x68; // EECP
+ s->mmio[0x0a] = 0x00;
+ s->mmio[0x0b] = 0x00;
+
+ s->irq = s->dev.irq[3];
+
+ // TODO - port registration is going to need an overhaul since ports
+ // can be low, full or high speed and are not tied to UHCI or EHCI.
+ // This works for now since we register last so are top of the free
+ // list but really all ports need to be owned by EHCI and it should
+ // hand off to companion controllers if device is full or low speed.
+
+ DPRINTF("ehci_init : registering USB ports with no device attached\n");
+
+ // TODO come up with a better port allocation scheme
+ // added ehci->bus, need to find ehci->DeviceState
+ usb_bus_new_v2(&s->bus, &s->dev.qdev);
+ for(i = 0; i < NB_PORTS; i++) {
+ usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
+ USB_SPEED_MASK_HIGH);
+ s->ports[i].dev = 0;
+ }
+
+ s->frame_timer = qemu_new_timer(vm_clock, ehci_frame_timer, s);
+
+ qemu_register_reset(ehci_reset, s);
+
+ s->mem = cpu_register_io_memory(ehci_readfn, ehci_writefn, s,
+ DEVICE_LITTLE_ENDIAN);
+
+ DPRINTF("ehci_init: registering MMIO size %d\n", MMIO_SIZE);
+ pci_register_bar(&s->dev, 0, MMIO_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ ehci_map);
+
+ fprintf(stderr, "\n\n*** EHCI support is under development *** \n\n");
+
+ return 0;
+}
+
+static void ehci_register(void)
+{
+ pci_qdev_register_many(ehci_info);
+}
+device_init(ehci_register);
+
+void usb_ehci_init(PCIBus *bus, int devfn)
+{
+ pci_create_simple(bus, devfn, "usb-ehci");
+}
+
+/*
+ * vim: expandtab ts=4
+ */
diff --git a/hw/usb-ehci.h b/hw/usb-ehci.h
new file mode 100644
index 0000000..ba087a0
--- /dev/null
+++ b/hw/usb-ehci.h
@@ -0,0 +1,8 @@
+#ifndef QEMU_USB_EHCI_H
+#define QEMU_USB_EHCI_H
+
+#include "qemu-common.h"
+
+void usb_ehci_init(PCIBus *bus, int devfn);
+
+#endif
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 76f5b02..48508ef 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -579,7 +579,7 @@ static USBDevice *usb_msd_init(const char *filename)
}
/* create guest device */
- dev = usb_create(NULL /* FIXME */, "usb-storage");
+ dev = usb_create_v2("usb-storage");
if (!dev) {
return NULL;
}
diff --git a/hw/usb-net.c b/hw/usb-net.c
index bf51bb3..8e67edd 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1405,7 +1405,7 @@ static USBDevice *usb_net_init(const char *cmdline)
return NULL;
}
- dev = usb_create(NULL /* FIXME */, "usb-net");
+ dev = usb_create_v1("usb-net");
if (!dev) {
return NULL;
}
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 09ea0b6..b5c9f86 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1696,7 +1696,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci->name = dev->info->name;
- usb_bus_new(&ohci->bus, dev);
+ usb_bus_new_v1(&ohci->bus, dev);
ohci->num_ports = num_ports;
for (i = 0; i < num_ports; i++) {
usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 6763d52..a476ccf 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -535,7 +535,7 @@ static USBDevice *usb_serial_init(const char *filename)
if (!cdrv)
return NULL;
- dev = usb_create(NULL /* FIXME */, "usb-serial");
+ dev = usb_create_v1("usb-serial");
if (!dev) {
return NULL;
}
@@ -558,7 +558,7 @@ static USBDevice *usb_braille_init(const char *unused)
if (!cdrv)
return NULL;
- dev = usb_create(NULL /* FIXME */, "usb-braille");
+ dev = usb_create_v1("usb-braille");
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
qdev_init_nofail(&dev->qdev);
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index b384e1d..c2d4f7a 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1127,7 +1127,7 @@ static int usb_uhci_common_initfn(UHCIState *s)
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
- usb_bus_new(&s->bus, &s->dev.qdev);
+ usb_bus_new_v1(&s->bus, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
diff --git a/hw/usb.h b/hw/usb.h
index d3d755d..282e700 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -341,18 +341,22 @@ struct USBBus {
int busnr;
int nfree;
int nused;
+ int version;
QTAILQ_HEAD(, USBPort) free;
QTAILQ_HEAD(, USBPort) used;
QTAILQ_ENTRY(USBBus) next;
};
-void usb_bus_new(USBBus *bus, DeviceState *host);
-USBBus *usb_bus_find(int busnr);
+void usb_bus_new_v1(USBBus *bus, DeviceState *host);
+void usb_bus_new_v2(USBBus *bus, DeviceState *host);
+USBBus *usb_bus_find_version(int version);
void usb_qdev_register(USBDeviceInfo *info);
void usb_qdev_register_many(USBDeviceInfo *info);
-USBDevice *usb_create(USBBus *bus, const char *name);
+USBDevice *usb_create_v1(const char *name);
+USBDevice *usb_create_v2(const char *name);
USBDevice *usb_create_simple(USBBus *bus, const char *name);
USBDevice *usbdevice_create(const char *cmdline);
+int usb_bus_migrate_v1(USBDevice *dev);
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
USBPortOps *ops, int speedmask);
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
diff --git a/monitor.c b/monitor.c
index fdbf9f3..c1f4d17 100644
--- a/monitor.c
+++ b/monitor.c
@@ -25,6 +25,7 @@
#include "hw/hw.h"
#include "hw/qdev.h"
#include "hw/usb.h"
+#include "hw/usb-ehci.h"
#include "hw/pcmcia.h"
#include "hw/pc.h"
#include "hw/pci.h"
diff --git a/usb-bsd.c b/usb-bsd.c
index abcb60c..7038024 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -362,7 +362,7 @@ USBDevice *usb_host_device_open(const char *devname)
goto fail_dfd;
}
- d = usb_create(NULL /* FIXME */, "usb-host");
+ d = usb_create_v1("usb-host");
dev = DO_UPCAST(USBHostDevice, dev, d);
if (dev_info.udi_speed == 1) {
diff --git a/usb-linux.c b/usb-linux.c
index ccf7073..6d58e5a 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -187,6 +187,8 @@ typedef struct AsyncURB
USBPacket *packet;
USBHostDevice *hdev;
+
+ int more; /* packet required multiple URBs */
} AsyncURB;
static AsyncURB *async_alloc(void)
@@ -252,7 +254,7 @@ static void async_complete(void *opaque)
if (p) {
switch (aurb->urb.status) {
case 0:
- p->len = aurb->urb.actual_length;
+ p->len += aurb->urb.actual_length;
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
async_complete_ctrl(s, p);
}
@@ -268,7 +270,10 @@ static void async_complete(void *opaque)
break;
}
- usb_packet_complete(p);
+ if (!aurb->more) {
+ DPRINTF("invoking packet_complete. plen = %d\n", p->len);
+ usb_packet_complete(p);
+ }
}
async_free(aurb);
@@ -414,69 +419,89 @@ static void usb_host_handle_destroy(USBDevice *dev)
static int usb_linux_update_endp_table(USBHostDevice *s);
+/* devio.c limits single requests to 16k */
+#define MAX_USBFS_BUFFER_SIZE 16384
+
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
{
struct usbdevfs_urb *urb;
AsyncURB *aurb;
- int ret;
+ int ret, len;
+ int rem = p->len;
+ uint8_t *pbuf = p->data;
- aurb = async_alloc();
- aurb->hdev = s;
- aurb->packet = p;
+ p->len = 0;
+ while (rem) {
+ aurb = async_alloc();
+ aurb->hdev = s;
+ aurb->packet = p;
- urb = &aurb->urb;
+ urb = &aurb->urb;
- if (p->pid == USB_TOKEN_IN) {
- urb->endpoint = p->devep | 0x80;
- } else {
- urb->endpoint = p->devep;
- }
+ if (p->pid == USB_TOKEN_IN) {
+ urb->endpoint = p->devep | 0x80;
+ } else {
+ urb->endpoint = p->devep;
+ }
- if (is_halted(s, p->devep)) {
- ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
- if (ret < 0) {
- DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
- urb->endpoint, errno);
- return USB_RET_NAK;
+ if (is_halted(s, p->devep)) {
+ ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
+ if (ret < 0) {
+ DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
+ urb->endpoint, errno);
+ return USB_RET_NAK;
+ }
+ clear_halt(s, p->devep);
}
- clear_halt(s, p->devep);
- }
- urb->buffer = p->data;
- urb->buffer_length = p->len;
+ if (is_isoc(s, p->devep)) {
+ /* Setup ISOC transfer */
+ urb->type = USBDEVFS_URB_TYPE_ISO;
+ urb->flags = USBDEVFS_URB_ISO_ASAP;
+ urb->number_of_packets = 1;
+ urb->iso_frame_desc[0].length = p->len;
+ } else {
+ /* Setup bulk transfer */
+ urb->type = USBDEVFS_URB_TYPE_BULK;
+ }
- if (is_isoc(s, p->devep)) {
- /* Setup ISOC transfer */
- urb->type = USBDEVFS_URB_TYPE_ISO;
- urb->flags = USBDEVFS_URB_ISO_ASAP;
- urb->number_of_packets = 1;
- urb->iso_frame_desc[0].length = p->len;
- } else {
- /* Setup bulk transfer */
- urb->type = USBDEVFS_URB_TYPE_BULK;
- }
+ urb->usercontext = s;
- urb->usercontext = s;
+ /* USBFS limits max request size to 16k */
+ if (rem > MAX_USBFS_BUFFER_SIZE) {
+ len = MAX_USBFS_BUFFER_SIZE;
+ aurb->more = 1;
+ } else {
+ len = rem;
+ aurb->more = 0;
+ }
+ urb->buffer_length = len;
+ urb->buffer = pbuf;
- ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
+ ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
- DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n",
- urb->endpoint, p->len, aurb);
+ DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n",
+ urb->endpoint, len, aurb);
- if (ret < 0) {
- DPRINTF("husb: submit failed. errno %d\n", errno);
- async_free(aurb);
+ if (ret < 0) {
+ DPRINTF("husb: submit failed. errno %d\n", errno);
+ async_free(aurb);
- switch(errno) {
- case ETIMEDOUT:
- return USB_RET_NAK;
- case EPIPE:
- default:
- return USB_RET_STALL;
+ switch(errno) {
+ case ETIMEDOUT:
+ return USB_RET_NAK;
+ case EPIPE:
+ default:
+ return USB_RET_STALL;
+ }
}
+
+ usb_defer_packet(p, async_cancel, aurb);
+
+ pbuf += len;
+ rem -= len;
}
- usb_defer_packet(p, async_cancel, aurb);
return USB_RET_ASYNC;
}
@@ -919,7 +944,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
static int usb_host_open(USBHostDevice *dev, int bus_num,
- int addr, int devpath, const char *prod_name)
+ int addr, int devpath, const char *prod_name,
+ int speed)
{
int fd = -1, ret;
struct usbdevfs_connectinfo ci;
@@ -983,17 +1009,17 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
goto fail;
}
- printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
+ printf("husb: grabbed usb device %d.%d, %s speed\n",
+ bus_num, addr, speed == USB_SPEED_HIGH ? "high":"low/full");
ret = usb_linux_update_endp_table(dev);
if (ret) {
goto fail;
}
- if (ci.slow) {
- dev->dev.speed = USB_SPEED_LOW;
- } else {
- dev->dev.speed = USB_SPEED_HIGH;
+ dev->dev.speed = speed;
+ if ( (speed != USB_SPEED_HIGH) && (usb_bus_migrate_v1(&dev->dev) != 0) ) {
+ goto fail;
}
if (!prod_name || prod_name[0] == '\0') {
@@ -1088,7 +1114,8 @@ USBDevice *usb_host_device_open(const char *devname)
USBDevice *dev;
char *p;
- dev = usb_create(NULL /* FIXME */, "usb-host");
+ /* default host devices to ehci */
+ dev = usb_create_v2("usb-host");
if (strstr(devname, "auto:")) {
if (parse_filter(devname, &filter) < 0) {
@@ -1507,7 +1534,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
}
DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
- usb_host_open(s, bus_num, addr, devpath, product_name);
+ usb_host_open(s, bus_num, addr, devpath, product_name, speed);
}
return 0;
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
@ 2011-03-09 15:40 erik.rull
2011-03-09 16:12 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: erik.rull @ 2011-03-09 15:40 UTC (permalink / raw)
To: kvm
Hi David,
looks really impressive.
It works and the performance is really good!
But some things are not working and cause my Windows guest to stop booting
or getting slowed down:
-device usb-tablet
-device usb-mouse
do not really work. (I have connected a PS/2 mouse to have no interference
with the rest of the USB system that works fine without the patch)
If I add them to the command line, windows does not boot up (it hangs
before the GUI comes up with ~ 12% CPU time on the host side)
If I add them at runtime via the qemu console it has no influence to the
guest - I still see no possibility grabbing the mouse to the client
-device usb-host
(for adding all USB devices automatically to the client) works only partly.
The client is slowed down when having activated this function but e.g. the
USB key gets detected - but not completely, Windows seem to hang somewhere
after having got the hardware and before displaying the key in the Explorer
(works without the patch)
If one of the above options are enabled I get sometimes a "USB Stall"
displayed in the qemu-console.
Additonally these lines appear:
ehci: PERIODIC list base register set while periodic schedule
and
ehci: ASYNC list address register set while async schedule
If I can help you or give you more feedback or even try out new patches,
just let me know.
I'm really interested in solving the "missing features".
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-09 15:40 erik.rull
@ 2011-03-09 16:12 ` David Ahern
2011-03-09 21:28 ` Erik Rull
0 siblings, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-03-09 16:12 UTC (permalink / raw)
To: erik.rull; +Cc: kvm
On 03/09/11 08:40, erik.rull@rdsoftware.de wrote:
> Hi David,
>
> looks really impressive.
> It works and the performance is really good!
>
> But some things are not working and cause my Windows guest to stop booting
> or getting slowed down:
> -device usb-tablet
> -device usb-mouse
> do not really work. (I have connected a PS/2 mouse to have no interference
> with the rest of the USB system that works fine without the patch)
> If I add them to the command line, windows does not boot up (it hangs
> before the GUI comes up with ~ 12% CPU time on the host side)
> If I add them at runtime via the qemu console it has no influence to the
> guest - I still see no possibility grabbing the mouse to the client
Did those work with the previous qemu-kvm releases you tested?
>
> -device usb-host
> (for adding all USB devices automatically to the client) works only partly.
> The client is slowed down when having activated this function but e.g. the
> USB key gets detected - but not completely, Windows seem to hang somewhere
> after having got the hardware and before displaying the key in the Explorer
> (works without the patch)
Similarly, how does this compare to prior qemu-kvm releases?
>
> If one of the above options are enabled I get sometimes a "USB Stall"
> displayed in the qemu-console.
> Additonally these lines appear:
> ehci: PERIODIC list base register set while periodic schedule
> and
> ehci: ASYNC list address register set while async schedule
According to the EHCI spec an OS is not allowed to do that when the
schedule and controller are enabled. It's more informational than
anything that OS is not compliant.
>
> If I can help you or give you more feedback or even try out new patches,
> just let me know.
> I'm really interested in solving the "missing features".
Someone needs to dig into the EHCI spec and the code. I lost momentum on
it last summer for various reasons.
David
>
> Best regards,
>
> Erik
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-09 16:12 ` David Ahern
@ 2011-03-09 21:28 ` Erik Rull
2011-03-09 22:14 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: Erik Rull @ 2011-03-09 21:28 UTC (permalink / raw)
To: David Ahern; +Cc: kvm
David Ahern wrote:
> On 03/09/11 08:40, erik.rull@rdsoftware.de wrote:
>> But some things are not working and cause my Windows guest to stop booting
>> or getting slowed down:
>> -device usb-tablet
>> -device usb-mouse
>> do not really work. (I have connected a PS/2 mouse to have no interference
>> with the rest of the USB system that works fine without the patch)
>> If I add them to the command line, windows does not boot up (it hangs
>> before the GUI comes up with ~ 12% CPU time on the host side)
>> If I add them at runtime via the qemu console it has no influence to the
>> guest - I still see no possibility grabbing the mouse to the client
>
> Did those work with the previous qemu-kvm releases you tested?
I've tried it long time ago with kvm-88, but there it was working but
extremely slow. (At least the mouse was reacting there)
>> -device usb-host
>> (for adding all USB devices automatically to the client) works only partly.
>> The client is slowed down when having activated this function but e.g. the
>> USB key gets detected - but not completely, Windows seem to hang somewhere
>> after having got the hardware and before displaying the key in the Explorer
>> (works without the patch)
>
> Similarly, how does this compare to prior qemu-kvm releases?
I'm not sure if that had worked with kvm-88 automatically - sorry.
>> If one of the above options are enabled I get sometimes a "USB Stall"
>> displayed in the qemu-console.
>> Additonally these lines appear:
>> ehci: PERIODIC list base register set while periodic schedule
>> and
>> ehci: ASYNC list address register set while async schedule
>
> According to the EHCI spec an OS is not allowed to do that when the
> schedule and controller are enabled. It's more informational than
> anything that OS is not compliant.
ok. (Windows is the OS :-))
>> If I can help you or give you more feedback or even try out new patches,
>> just let me know.
>> I'm really interested in solving the "missing features".
>
> Someone needs to dig into the EHCI spec and the code. I lost momentum on
> it last summer for various reasons.
>
> David
>
Hm, okay.
As far as I understood it, the auto-add feature should be similar to the
USB 1.1, right? It seems to work basically but not fully - the system is
somehow slowed down, maybe the polling timer is too fast? (I will play a
little bit with that and review and compare as well the auto routine)
And the usb-tablet should be an uhci-emulated component, that should then
not interfere with the ehci-emulation, right?
If you have any additional hints where to start digging, just let me know.
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-09 21:28 ` Erik Rull
@ 2011-03-09 22:14 ` David Ahern
2011-03-09 22:48 ` Erik Rull
0 siblings, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-03-09 22:14 UTC (permalink / raw)
To: Erik Rull; +Cc: kvm
On 03/09/11 14:28, Erik Rull wrote:
> David Ahern wrote:
>> On 03/09/11 08:40, erik.rull@rdsoftware.de wrote:
>>> But some things are not working and cause my Windows guest to stop
>>> booting
>>> or getting slowed down:
>>> -device usb-tablet
>>> -device usb-mouse
>>> do not really work. (I have connected a PS/2 mouse to have no
>>> interference
>>> with the rest of the USB system that works fine without the patch)
>>> If I add them to the command line, windows does not boot up (it hangs
>>> before the GUI comes up with ~ 12% CPU time on the host side)
>>> If I add them at runtime via the qemu console it has no influence to the
>>> guest - I still see no possibility grabbing the mouse to the client
>>
>> Did those work with the previous qemu-kvm releases you tested?
>
> I've tried it long time ago with kvm-88, but there it was working but
> extremely slow. (At least the mouse was reacting there)
I thought you tried the EHCI patch against a recent qemu-kvm version --
like December 2010 or January 2011.
> Hm, okay.
> As far as I understood it, the auto-add feature should be similar to the
> USB 1.1, right? It seems to work basically but not fully - the system is
> somehow slowed down, maybe the polling timer is too fast? (I will play a
> little bit with that and review and compare as well the auto routine)
>
> And the usb-tablet should be an uhci-emulated component, that should
> then not interfere with the ehci-emulation, right?
My proposal from July 2010 was to have emulated devices state their
version and have host devices try EHCI then UHCI. This means that the
tablet device is attached to UHCI and a host USB key is attached to
EHCI. Like this:
info usb
Device 0.1, Port 1, Speed 12 Mb/s, Product QEMU USB Tablet
Device 1.1, Port , Speed 480 Mb/s, Product DT 101 II
(qemu)
That's what the patch I sent does.
EHCI does have a lot higher frame rate and in its current form does have
a noticeable impact on CPU usage when devices are connected and one of
the lists is activated. If the OS deactivates the controller when there
is nothing to do (e.g., not actively talking to the device), cpu usage
goes down.
I just tried a few scenarios with the X and V versions of those GUI
based guests and an external key attached to EHCI bus worked fine and
the usb tablet also worked fine.
I did notice some differences in command syntax. For instance, my
scripts still use the older -usbdevice tablet syntax and I did not see
the USB stall message. Switching to '-device usb-tablet' did generate
the message at boot (though overall it seems to be harmless).
Nothing fancy with the setup -- ide drive, virtio or e1000 networking,
ac97 sound, no-hpet and usb tablet devices.
In the time it took to write this response about 900MB was transferred
to the usb key at about 1.7-1.8MB/sec rate.
David
>
> If you have any additional hints where to start digging, just let me know.
>
> Best regards,
>
> Erik
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-09 22:14 ` David Ahern
@ 2011-03-09 22:48 ` Erik Rull
0 siblings, 0 replies; 30+ messages in thread
From: Erik Rull @ 2011-03-09 22:48 UTC (permalink / raw)
To: David Ahern; +Cc: kvm
David Ahern wrote:
>
>
> On 03/09/11 14:28, Erik Rull wrote:
>> David Ahern wrote:
>> I've tried it long time ago with kvm-88, but there it was working but
>> extremely slow. (At least the mouse was reacting there)
>
> I thought you tried the EHCI patch against a recent qemu-kvm version --
> like December 2010 or January 2011.
Yes, this time I patched against 0.14.0, I misunderstood your question, sorry.
My last attempt before that was kvm-88.
>> Hm, okay.
>> As far as I understood it, the auto-add feature should be similar to the
>> USB 1.1, right? It seems to work basically but not fully - the system is
>> somehow slowed down, maybe the polling timer is too fast? (I will play a
>> little bit with that and review and compare as well the auto routine)
>>
>> And the usb-tablet should be an uhci-emulated component, that should
>> then not interfere with the ehci-emulation, right?
>
> My proposal from July 2010 was to have emulated devices state their
> version and have host devices try EHCI then UHCI. This means that the
> tablet device is attached to UHCI and a host USB key is attached to
> EHCI. Like this:
>
> info usb
> Device 0.1, Port 1, Speed 12 Mb/s, Product QEMU USB Tablet
> Device 1.1, Port , Speed 480 Mb/s, Product DT 101 II
> (qemu)
>
> That's what the patch I sent does.
>
> EHCI does have a lot higher frame rate and in its current form does have
> a noticeable impact on CPU usage when devices are connected and one of
> the lists is activated. If the OS deactivates the controller when there
> is nothing to do (e.g., not actively talking to the device), cpu usage
> goes down.
Thanks for the explanation!
> I just tried a few scenarios with the X and V versions of those GUI
> based guests and an external key attached to EHCI bus worked fine and
> the usb tablet also worked fine.
>
> I did notice some differences in command syntax. For instance, my
> scripts still use the older -usbdevice tablet syntax and I did not see
> the USB stall message. Switching to '-device usb-tablet' did generate
> the message at boot (though overall it seems to be harmless).
>
> Nothing fancy with the setup -- ide drive, virtio or e1000 networking,
> ac97 sound, no-hpet and usb tablet devices.
>
> In the time it took to write this response about 900MB was transferred
> to the usb key at about 1.7-1.8MB/sec rate.
>
> David
I will give it another try tomorrow. I use
-usb -device usb-tablet -device usb-host
The last parameter for the auto-add to the guest
I will also try the old parameter syntax.
What does the no-hpet option do? Might this be somehow significant
regarding the performance?
Best regards,
Erik
P.S.
When EHCI was active today without tablet and without auto-add I got a
transfer rate of ~5MByte/sec from USB key to the HDD.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
@ 2011-03-11 15:18 erik.rull
2011-03-11 15:39 ` Markus Armbruster
2011-03-11 15:57 ` David Ahern
0 siblings, 2 replies; 30+ messages in thread
From: erik.rull @ 2011-03-11 15:18 UTC (permalink / raw)
To: kvm
Hi David,
I did a second iteration and it looked way better, maybe my first attempts
were somehow buggy.
First - please review your DPRINTF in the usb-ehci.c, there is a variable
"dev" undefined in line 504/505 when enabling the debugging defines at the
top of the file, the compiler complains there.
I tested again with your hints, here my results:
- using -device usb-host causes windows not to boot completely, using
-usbdevice host:auto:*.* is fine!
- using -usbdevice tablet is better than using -device usb-tablet
- only one "external" USB device gets detected, the rest is just ignored.
qemu does not recognize the device, but the host OS sees it (dmesg output)
- if the first plugged in device is removed from the usb port and the
second (not detected one) is still plugged in, then this second device gets
now detected by qemu and is handled to the guest
Additionally something really interesting:
if I disable USB 2.0 in my host BIOS and boot my guest system with the qemu
ehci patch, then I get no longer the BSOD in windows when removing the
printer! :-) So the patch seems also to improve the usb-uhci stuff.
So everything is fine now beside the "more than one USB device" issue.
Any ideas what this could be?
Thanks a lot for your support!
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 15:18 USB EHCI patch for 0.14.0? erik.rull
@ 2011-03-11 15:39 ` Markus Armbruster
2011-03-11 16:01 ` David Ahern
2011-03-11 16:24 ` Erik Rull
2011-03-11 15:57 ` David Ahern
1 sibling, 2 replies; 30+ messages in thread
From: Markus Armbruster @ 2011-03-11 15:39 UTC (permalink / raw)
To: erik.rull; +Cc: kvm
erik.rull@rdsoftware.de writes:
> Hi David,
>
> I did a second iteration and it looked way better, maybe my first attempts
> were somehow buggy.
>
> First - please review your DPRINTF in the usb-ehci.c, there is a variable
> "dev" undefined in line 504/505 when enabling the debugging defines at the
> top of the file, the compiler complains there.
>
> I tested again with your hints, here my results:
>
> - using -device usb-host causes windows not to boot completely, using
> -usbdevice host:auto:*.* is fine!
>
> - using -usbdevice tablet is better than using -device usb-tablet
Better inhowfar?
[...]
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 15:18 USB EHCI patch for 0.14.0? erik.rull
2011-03-11 15:39 ` Markus Armbruster
@ 2011-03-11 15:57 ` David Ahern
2011-03-11 16:32 ` Erik Rull
1 sibling, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-03-11 15:57 UTC (permalink / raw)
To: erik.rull; +Cc: kvm
On 03/11/11 08:18, erik.rull@rdsoftware.de wrote:
> Hi David,
>
> I did a second iteration and it looked way better, maybe my first attempts
> were somehow buggy.
>
> First - please review your DPRINTF in the usb-ehci.c, there is a variable
> "dev" undefined in line 504/505 when enabling the debugging defines at the
> top of the file, the compiler complains there.
Args to that function was changed recently; I just deleted the printf.
>
> I tested again with your hints, here my results:
>
> - using -device usb-host causes windows not to boot completely, using
> -usbdevice host:auto:*.* is fine!
>
> - using -usbdevice tablet is better than using -device usb-tablet
>
>
> - only one "external" USB device gets detected, the rest is just ignored.
> qemu does not recognize the device, but the host OS sees it (dmesg output)
I have not used the auto feature. What happens if you disable it and
instead add the devices you want? I have been able to add both a printer
and a USB key to a guest -- both on the EHCI bus. And just verified
again - both printer and USB key accessible within the guest.
>
> - if the first plugged in device is removed from the usb port and the
> second (not detected one) is still plugged in, then this second device gets
> now detected by qemu and is handled to the guest
Interesting. Gerd made a lot of changes to the USB code right before
0.14. I have not really followed the change set - or how it might impact
ehci. It could be a bug independent of ehci as well -- try it without
the ehci patch and see if the same occurs.
>
> Additionally something really interesting:
> if I disable USB 2.0 in my host BIOS and boot my guest system with the qemu
> ehci patch, then I get no longer the BSOD in windows when removing the
> printer! :-) So the patch seems also to improve the usb-uhci stuff.
Our mileage differs here as well. I'm running Fedora 14 on my laptop.
With the ehci enabled version of qemu-kvm I have no problems connecting
and disconnecting devices -- host or guest.
David
>
> So everything is fine now beside the "more than one USB device" issue.
>
> Any ideas what this could be?
>
> Thanks a lot for your support!
>
> Best regards,
>
> Erik
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 15:39 ` Markus Armbruster
@ 2011-03-11 16:01 ` David Ahern
2011-03-11 16:17 ` Markus Armbruster
2011-03-11 16:24 ` Erik Rull
1 sibling, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-03-11 16:01 UTC (permalink / raw)
To: Markus Armbruster; +Cc: erik.rull, kvm
On 03/11/11 08:39, Markus Armbruster wrote:
> erik.rull@rdsoftware.de writes:
>
>> Hi David,
>>
>> I did a second iteration and it looked way better, maybe my first attempts
>> were somehow buggy.
>>
>> First - please review your DPRINTF in the usb-ehci.c, there is a variable
>> "dev" undefined in line 504/505 when enabling the debugging defines at the
>> top of the file, the compiler complains there.
>>
>> I tested again with your hints, here my results:
>>
>> - using -device usb-host causes windows not to boot completely, using
>> -usbdevice host:auto:*.* is fine!
>>
>> - using -usbdevice tablet is better than using -device usb-tablet
>
> Better inhowfar?
As I recall the USB code is the ignored step-child in qemu; it was never
properly/fully integrated into the qdev stuff. The paths appear to
differ in how usb devices are handled. I for one have always stuck with
the -usbdevice route.
David
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 16:01 ` David Ahern
@ 2011-03-11 16:17 ` Markus Armbruster
2011-03-11 16:34 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: Markus Armbruster @ 2011-03-11 16:17 UTC (permalink / raw)
To: David Ahern; +Cc: erik.rull, kvm
David Ahern <daahern@cisco.com> writes:
> On 03/11/11 08:39, Markus Armbruster wrote:
>> erik.rull@rdsoftware.de writes:
>>
>>> Hi David,
>>>
>>> I did a second iteration and it looked way better, maybe my first attempts
>>> were somehow buggy.
>>>
>>> First - please review your DPRINTF in the usb-ehci.c, there is a variable
>>> "dev" undefined in line 504/505 when enabling the debugging defines at the
>>> top of the file, the compiler complains there.
>>>
>>> I tested again with your hints, here my results:
>>>
>>> - using -device usb-host causes windows not to boot completely, using
>>> -usbdevice host:auto:*.* is fine!
>>>
>>> - using -usbdevice tablet is better than using -device usb-tablet
>>
>> Better inhowfar?
>
> As I recall the USB code is the ignored step-child in qemu; it was never
> properly/fully integrated into the qdev stuff. The paths appear to
> differ in how usb devices are handled. I for one have always stuck with
> the -usbdevice route.
Please report any deficiencies so we can fix this.
-usbdevice is around for backward compatibility only. There are already
cases where -device provides you more control than -usbdevice. This
feature gap will only grow.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 15:39 ` Markus Armbruster
2011-03-11 16:01 ` David Ahern
@ 2011-03-11 16:24 ` Erik Rull
2011-03-11 16:46 ` Markus Armbruster
1 sibling, 1 reply; 30+ messages in thread
From: Erik Rull @ 2011-03-11 16:24 UTC (permalink / raw)
To: Markus Armbruster; +Cc: kvm
Markus Armbruster wrote:
> erik.rull@rdsoftware.de writes:
>
>> Hi David,
>>
>> I did a second iteration and it looked way better, maybe my first attempts
>> were somehow buggy.
>>
>> First - please review your DPRINTF in the usb-ehci.c, there is a variable
>> "dev" undefined in line 504/505 when enabling the debugging defines at the
>> top of the file, the compiler complains there.
>>
>> I tested again with your hints, here my results:
>>
>> - using -device usb-host causes windows not to boot completely, using
>> -usbdevice host:auto:*.* is fine!
>>
>> - using -usbdevice tablet is better than using -device usb-tablet
>
> Better inhowfar?
>
> [...]
It seems to work fine, the other option caused either windows not to boot
fully or the auto grabbing itself doesn't seem to work or the mouse just
didn't move. I experienced all of the three, but I haven't noted down in
which combinations - sorry.
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 15:57 ` David Ahern
@ 2011-03-11 16:32 ` Erik Rull
0 siblings, 0 replies; 30+ messages in thread
From: Erik Rull @ 2011-03-11 16:32 UTC (permalink / raw)
To: David Ahern; +Cc: kvm
David Ahern wrote:
> On 03/11/11 08:18, erik.rull@rdsoftware.de wrote:
>>
>> I tested again with your hints, here my results:
>>
>> - using -device usb-host causes windows not to boot completely, using
>> -usbdevice host:auto:*.* is fine!
>>
>> - using -usbdevice tablet is better than using -device usb-tablet
>>
>>
>> - only one "external" USB device gets detected, the rest is just ignored.
>> qemu does not recognize the device, but the host OS sees it (dmesg output)
>
> I have not used the auto feature. What happens if you disable it and
> instead add the devices you want? I have been able to add both a printer
> and a USB key to a guest -- both on the EHCI bus. And just verified
> again - both printer and USB key accessible within the guest.
I will test that on monday and will let you know about the results.
>> - if the first plugged in device is removed from the usb port and the
>> second (not detected one) is still plugged in, then this second device gets
>> now detected by qemu and is handled to the guest
>
> Interesting. Gerd made a lot of changes to the USB code right before
> 0.14. I have not really followed the change set - or how it might impact
> ehci. It could be a bug independent of ehci as well -- try it without
> the ehci patch and see if the same occurs.
Very good point :-) I've never tested that because I knew that the USB
printer will then crash my guest :-)
But I will follow that idea on monday as well.
>> Additionally something really interesting:
>> if I disable USB 2.0 in my host BIOS and boot my guest system with the qemu
>> ehci patch, then I get no longer the BSOD in windows when removing the
>> printer! :-) So the patch seems also to improve the usb-uhci stuff.
>
> Our mileage differs here as well. I'm running Fedora 14 on my laptop.
> With the ehci enabled version of qemu-kvm I have no problems connecting
> and disconnecting devices -- host or guest.
Except the not fully functioning auto add feature we're on the same level,
because I've not tested the manual adding (and I assume / hope that it will
be successful).
>
> David
>
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 16:17 ` Markus Armbruster
@ 2011-03-11 16:34 ` David Ahern
0 siblings, 0 replies; 30+ messages in thread
From: David Ahern @ 2011-03-11 16:34 UTC (permalink / raw)
To: Markus Armbruster; +Cc: erik.rull, kvm
On 03/11/11 09:17, Markus Armbruster wrote:
> David Ahern <daahern@cisco.com> writes:
>
>> On 03/11/11 08:39, Markus Armbruster wrote:
>>> erik.rull@rdsoftware.de writes:
>>>
>>>> Hi David,
>>>>
>>>> I did a second iteration and it looked way better, maybe my first attempts
>>>> were somehow buggy.
>>>>
>>>> First - please review your DPRINTF in the usb-ehci.c, there is a variable
>>>> "dev" undefined in line 504/505 when enabling the debugging defines at the
>>>> top of the file, the compiler complains there.
>>>>
>>>> I tested again with your hints, here my results:
>>>>
>>>> - using -device usb-host causes windows not to boot completely, using
>>>> -usbdevice host:auto:*.* is fine!
>>>>
>>>> - using -usbdevice tablet is better than using -device usb-tablet
>>>
>>> Better inhowfar?
>>
>> As I recall the USB code is the ignored step-child in qemu; it was never
>> properly/fully integrated into the qdev stuff. The paths appear to
>> differ in how usb devices are handled. I for one have always stuck with
>> the -usbdevice route.
>
> Please report any deficiencies so we can fix this.
Erik reported a few above.
David
>
> -usbdevice is around for backward compatibility only. There are already
> cases where -device provides you more control than -usbdevice. This
> feature gap will only grow.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 16:24 ` Erik Rull
@ 2011-03-11 16:46 ` Markus Armbruster
2011-03-11 16:56 ` Erik Rull
0 siblings, 1 reply; 30+ messages in thread
From: Markus Armbruster @ 2011-03-11 16:46 UTC (permalink / raw)
To: Erik Rull; +Cc: kvm
Erik Rull <erik.rull@rdsoftware.de> writes:
> Markus Armbruster wrote:
>> erik.rull@rdsoftware.de writes:
>>
>>> Hi David,
>>>
>>> I did a second iteration and it looked way better, maybe my first attempts
>>> were somehow buggy.
>>>
>>> First - please review your DPRINTF in the usb-ehci.c, there is a variable
>>> "dev" undefined in line 504/505 when enabling the debugging defines at the
>>> top of the file, the compiler complains there.
>>>
>>> I tested again with your hints, here my results:
>>>
>>> - using -device usb-host causes windows not to boot completely, using
>>> -usbdevice host:auto:*.* is fine!
>>>
>>> - using -usbdevice tablet is better than using -device usb-tablet
>>
>> Better inhowfar?
>>
>> [...]
>
> It seems to work fine, the other option caused either windows not to
> boot fully or the auto grabbing itself doesn't seem to work or the
> mouse just didn't move. I experienced all of the three, but I haven't
> noted down in which combinations - sorry.
Please provide recipes to reproduce the bugs.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 16:46 ` Markus Armbruster
@ 2011-03-11 16:56 ` Erik Rull
2011-03-11 17:11 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: Erik Rull @ 2011-03-11 16:56 UTC (permalink / raw)
To: Markus Armbruster; +Cc: kvm@vger.kernel.org
Markus Armbruster wrote:
> Erik Rull<erik.rull@rdsoftware.de> writes:
>
>> Markus Armbruster wrote:
>>> erik.rull@rdsoftware.de writes:
>>>
>>>> - using -device usb-host causes windows not to boot completely, using
>>>> -usbdevice host:auto:*.* is fine!
>>>>
>>>> - using -usbdevice tablet is better than using -device usb-tablet
>>>
>>> Better inhowfar?
>>>
>>> [...]
>>
>> It seems to work fine, the other option caused either windows not to
>> boot fully or the auto grabbing itself doesn't seem to work or the
>> mouse just didn't move. I experienced all of the three, but I haven't
>> noted down in which combinations - sorry.
>
> Please provide recipes to reproduce the bugs.
- take Windows XP 32 bit SP3 as Guest
- apply the ehci patch to qemu-kvm-0.14.0 (David posted it here some days ago)
boot the guest using the command line args:
-usb -device usb-host
(I also tried the proposal where the additonal usb-host options are all set
to 0, same result)
Windows starts but hangs before the GUI comes up (I boot without logo, so
the white bar that comes up when booting stays for > 20 minutes (I aborted
afterwards)), the CPU usage on a Core2Duo system goes to ~10-14%.
If I use instead
-usb -usbdevice host:auto:*.*
everything is fine!
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 16:56 ` Erik Rull
@ 2011-03-11 17:11 ` David Ahern
2011-03-11 17:31 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-03-11 17:11 UTC (permalink / raw)
To: Erik Rull; +Cc: Markus Armbruster, kvm@vger.kernel.org
On 03/11/11 09:56, Erik Rull wrote:
> Markus Armbruster wrote:
>> Erik Rull<erik.rull@rdsoftware.de> writes:
>>
>>> Markus Armbruster wrote:
>>>> erik.rull@rdsoftware.de writes:
>>>>
>>>>> - using -device usb-host causes windows not to boot completely, using
>>>>> -usbdevice host:auto:*.* is fine!
>>>>>
>>>>> - using -usbdevice tablet is better than using -device usb-tablet
>>>>
>>>> Better inhowfar?
>>>>
>>>> [...]
>>>
>>> It seems to work fine, the other option caused either windows not to
>>> boot fully or the auto grabbing itself doesn't seem to work or the
>>> mouse just didn't move. I experienced all of the three, but I haven't
>>> noted down in which combinations - sorry.
>>
>> Please provide recipes to reproduce the bugs.
>
> - take Windows XP 32 bit SP3 as Guest
> - apply the ehci patch to qemu-kvm-0.14.0 (David posted it here some
> days ago)
processing of usb device options is independent of the EHCI patch.
David
> boot the guest using the command line args:
> -usb -device usb-host
> (I also tried the proposal where the additonal usb-host options are all
> set to 0, same result)
> Windows starts but hangs before the GUI comes up (I boot without logo,
> so the white bar that comes up when booting stays for > 20 minutes (I
> aborted afterwards)), the CPU usage on a Core2Duo system goes to ~10-14%.
>
> If I use instead
> -usb -usbdevice host:auto:*.*
> everything is fine!
>
> Best regards,
>
> Erik
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 17:11 ` David Ahern
@ 2011-03-11 17:31 ` David Ahern
2011-04-11 9:40 ` ya su
0 siblings, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-03-11 17:31 UTC (permalink / raw)
To: Erik Rull; +Cc: Markus Armbruster, kvm@vger.kernel.org
On 03/11/11 10:11, David Ahern wrote:
>
>
> On 03/11/11 09:56, Erik Rull wrote:
>> Markus Armbruster wrote:
>>> Erik Rull<erik.rull@rdsoftware.de> writes:
>>>
>>>> Markus Armbruster wrote:
>>>>> erik.rull@rdsoftware.de writes:
>>>>>
>>>>>> - using -device usb-host causes windows not to boot completely, using
>>>>>> -usbdevice host:auto:*.* is fine!
>>>>>>
>>>>>> - using -usbdevice tablet is better than using -device usb-tablet
>>>>>
>>>>> Better inhowfar?
>>>>>
>>>>> [...]
>>>>
>>>> It seems to work fine, the other option caused either windows not to
>>>> boot fully or the auto grabbing itself doesn't seem to work or the
>>>> mouse just didn't move. I experienced all of the three, but I haven't
>>>> noted down in which combinations - sorry.
>>>
>>> Please provide recipes to reproduce the bugs.
>>
>> - take Windows XP 32 bit SP3 as Guest
>> - apply the ehci patch to qemu-kvm-0.14.0 (David posted it here some
>> days ago)
>
> processing of usb device options is independent of the EHCI patch.
>
> David
>
>> boot the guest using the command line args:
>> -usb -device usb-host
>> (I also tried the proposal where the additonal usb-host options are all
>> set to 0, same result)
>> Windows starts but hangs before the GUI comes up (I boot without logo,
>> so the white bar that comes up when booting stays for > 20 minutes (I
>> aborted afterwards)), the CPU usage on a Core2Duo system goes to ~10-14%.
Ok, this is case is caused by the EHCI patch. Works fine with UHCI only.
I'll look into it when I have time. For now use the usbdevice path.
David
>>
>> If I use instead
>> -usb -usbdevice host:auto:*.*
>> everything is fine!
>>
>> Best regards,
>>
>> Erik
>> --
>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
@ 2011-03-14 8:38 erik.rull
2011-03-17 18:05 ` Erik Rull
0 siblings, 1 reply; 30+ messages in thread
From: erik.rull @ 2011-03-14 8:38 UTC (permalink / raw)
To: kvm
Hi all,
I've tested the following:
- EHCI patch without auto_add and adding the devices manually
Result:
Works fine, all devices could be added. I've tested only 2 but it is more
than with the auto_add feature :-)
- UHCI only (no EHCI patch) with enabled "-device usb-host"
Result:
Same as with EHCI-Patch and enabled auto_add! Only ONE device gets detected.
info usb shows two (tablet and one hardware usb device)
info usbhost shows two hardware devices (+ the complete host controller
set), where the second one does not get detected by qemu-kvm until the
first device gets removed. If I then plug in again the first device, it
does not get detected until the second gets removed (and so on)
So the auto-add seems to be buggy in all configurations, it does not seem
to be related with the EHCI-patch (that's my thought at this point).
Best regards,
Erik
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-14 8:38 erik.rull
@ 2011-03-17 18:05 ` Erik Rull
0 siblings, 0 replies; 30+ messages in thread
From: Erik Rull @ 2011-03-17 18:05 UTC (permalink / raw)
To: kvm; +Cc: David Ahern, Markus Armbruster
erik.rull@rdsoftware.de wrote:
> Hi all,
>
> I've tested the following:
>
> - EHCI patch without auto_add and adding the devices manually
> Result:
> Works fine, all devices could be added. I've tested only 2 but it is more
> than with the auto_add feature :-)
>
> - UHCI only (no EHCI patch) with enabled "-device usb-host"
> Result:
> Same as with EHCI-Patch and enabled auto_add! Only ONE device gets detected.
> info usb shows two (tablet and one hardware usb device)
> info usbhost shows two hardware devices (+ the complete host controller
> set), where the second one does not get detected by qemu-kvm until the
> first device gets removed. If I then plug in again the first device, it
> does not get detected until the second gets removed (and so on)
>
> So the auto-add seems to be buggy in all configurations, it does not seem
> to be related with the EHCI-patch (that's my thought at this point).
>
> Best regards,
>
> Erik
>
Has there been a progress or idea how to proceed on the reported things?
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-11 17:31 ` David Ahern
@ 2011-04-11 9:40 ` ya su
2011-04-11 13:23 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: ya su @ 2011-04-11 9:40 UTC (permalink / raw)
To: David Ahern; +Cc: Erik Rull, Markus Armbruster, kvm@vger.kernel.org
David:
I have applied the patch to 0.14.0, and there is a bug if I add a
optiarc CRRWDVD CRX890A usb device on windows xp, I first comment out
the following code in usb-linux.c:
if (is_halted(s, p->devep)) {
ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
#if 0
if (ret < 0) {
DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
urb->endpoint, errno);
return USB_RET_NAK;
}
#endif
clear_halt(s, p->devep);
}
then it can continue to run in linux, but still stall on windows
xp and win7. I turn on debug, part of the output is as the following:
husb: async cancel. aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status -2 alen 0
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 64
husb: submit ctrl. len 72 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x0 req 0x5 val 0x2 index 0 len 0
husb: ctrl set addr 2
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 18
husb: submit ctrl. len 26 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: ctrl type 0x0 req 0x9 val 0x1 index 0 len 0
husb: releasing interfaces
husb: ctrl set config 1 ret 0 errno 11
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 64 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 4
invoking packet_complete. plen = 4
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status -32 alen 0
invoking packet_complete. plen = -3
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 64
husb: submit ctrl. len 72 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x0 req 0x5 val 0x1 index 0 len 0
husb: ctrl set addr 1
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 18
husb: submit ctrl. len 26 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: ctrl type 0x0 req 0x9 val 0x1 index 0 len 0
husb: releasing interfaces
husb: ctrl set config 1 ret 0 errno 11
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 64 aurb 0x1616cd0
[Thread 0x7ffff4f75710 (LWP 3317) exited]
husb: async completed. aurb 0x1616cd0 status 0 alen 4
invoking packet_complete. plen = 4
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async cancel. aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status -2 alen 0
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 64
husb: submit ctrl. len 72 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x0 req 0x5 val 0x2 index 0 len 0
husb: ctrl set addr 2
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 18
husb: submit ctrl. len 26 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: ctrl type 0x0 req 0x9 val 0x1 index 0 len 0
husb: releasing interfaces
husb: ctrl set config 1 ret 0 errno 11
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 40 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 16
invoking packet_complete. plen = 16
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status -32 alen 0
invoking packet_complete. plen = -3
it seems that windows driver always fail and try again. I can find
the device on device manager, but can not load the contents of disc.
if it run on linux, it will meet the same error, but it can
continue to work, and can mount the disc to see the contents. the
output is as the following:
invoking packet_complete. plen = -3
husb: ctrl type 0x2 req 0x1 val 0x0 index 129 len 0
husb: submit ctrl. len 8 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 0
invoking packet_complete. plen = 0
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async cancel. aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status -2 alen 0
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 64
husb: submit ctrl. len 72 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: reset device 6.8
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x0 req 0x5 val 0x2 index 0 len 0
husb: ctrl set addr 2
husb: ctrl type 0x80 req 0x6 val 0x100 index 0 len 18
husb: submit ctrl. len 26 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 18
invoking packet_complete. plen = 8
husb: ctrl type 0x80 req 0x6 val 0x200 index 0 len 32
husb: submit ctrl. len 40 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 32
invoking packet_complete. plen = 8
husb: ctrl type 0x0 req 0x9 val 0x1 index 0 len 0
husb: releasing interfaces
husb: ctrl set config 1 ret 0 errno 11
husb: claiming interfaces. config 1
husb: i is 18, descr_len is 50, dl 9, dt 2
husb: config #1 need 1
husb: 1 interfaces claimed for configuration 1
husb: ctrl type 0x1 req 0xb val 0x0 index 0 len 0
husb: ctrl set iface 0 altset 0 ret 0 errno 11
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 12 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 12
invoking packet_complete. plen = 12
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 12 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 12
invoking packet_complete. plen = 12
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 12 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 12
invoking packet_complete. plen = 12
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 8 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 8
invoking packet_complete. plen = 8
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
husb: data submit. ep 0x2 len 31 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 31
invoking packet_complete. plen = 31
husb: data submit. ep 0x81 len 13 aurb 0x1616cd0
husb: async completed. aurb 0x1616cd0 status 0 alen 13
invoking packet_complete. plen = 13
I wonder if this is the bug of windows driver, or can be fixed in
this patch? thanks.
Regards.
Green.
2011/3/12 David Ahern <daahern@cisco.com>:
>
>
> On 03/11/11 10:11, David Ahern wrote:
>>
>>
>> On 03/11/11 09:56, Erik Rull wrote:
>>> Markus Armbruster wrote:
>>>> Erik Rull<erik.rull@rdsoftware.de> writes:
>>>>
>>>>> Markus Armbruster wrote:
>>>>>> erik.rull@rdsoftware.de writes:
>>>>>>
>>>>>>> - using -device usb-host causes windows not to boot completely, using
>>>>>>> -usbdevice host:auto:*.* is fine!
>>>>>>>
>>>>>>> - using -usbdevice tablet is better than using -device usb-tablet
>>>>>>
>>>>>> Better inhowfar?
>>>>>>
>>>>>> [...]
>>>>>
>>>>> It seems to work fine, the other option caused either windows not to
>>>>> boot fully or the auto grabbing itself doesn't seem to work or the
>>>>> mouse just didn't move. I experienced all of the three, but I haven't
>>>>> noted down in which combinations - sorry.
>>>>
>>>> Please provide recipes to reproduce the bugs.
>>>
>>> - take Windows XP 32 bit SP3 as Guest
>>> - apply the ehci patch to qemu-kvm-0.14.0 (David posted it here some
>>> days ago)
>>
>> processing of usb device options is independent of the EHCI patch.
>>
>> David
>>
>>> boot the guest using the command line args:
>>> -usb -device usb-host
>>> (I also tried the proposal where the additonal usb-host options are all
>>> set to 0, same result)
>>> Windows starts but hangs before the GUI comes up (I boot without logo,
>>> so the white bar that comes up when booting stays for > 20 minutes (I
>>> aborted afterwards)), the CPU usage on a Core2Duo system goes to ~10-14%.
>
> Ok, this is case is caused by the EHCI patch. Works fine with UHCI only.
> I'll look into it when I have time. For now use the usbdevice path.
>
> David
>
>
>>>
>>> If I use instead
>>> -usb -usbdevice host:auto:*.*
>>> everything is fine!
>>>
>>> Best regards,
>>>
>>> Erik
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-04-11 9:40 ` ya su
@ 2011-04-11 13:23 ` David Ahern
2011-04-11 16:32 ` Jan Kiszka
2011-04-11 16:46 ` Jan Kiszka
0 siblings, 2 replies; 30+ messages in thread
From: David Ahern @ 2011-04-11 13:23 UTC (permalink / raw)
To: ya su; +Cc: Erik Rull, Markus Armbruster, kvm@vger.kernel.org
On 04/11/11 03:40, ya su wrote:
> David:
>
> I have applied the patch to 0.14.0, and there is a bug if I add a
> optiarc CRRWDVD CRX890A usb device on windows xp, I first comment out
> the following code in usb-linux.c:
>
> if (is_halted(s, p->devep)) {
> ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
> #if 0
> if (ret < 0) {
> DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
> urb->endpoint, errno);
> return USB_RET_NAK;
> }
> #endif
> clear_halt(s, p->devep);
> }
>
> then it can continue to run in linux, but still stall on windows
> xp and win7. I turn on debug, part of the output is as the following:
The EHCI code is very rough and needs someone to step up and finish it.
It seems to work ok for USB storage devices (keys and drives), and seems
to work fine with printers and scanners (at least it works with mine
;-)). I see stalls from time to time, but it recovers and continues on.
Clearly some touchups are needed.
On the other end it is known not to work with any audio and video
devices (webcams, iphones).
Something like the DVD I have no idea - never tried.
I lost momentum on the code last August and have not been able to get
back to it for a variety of reasons. It really needs someone to pick it
up and continue - or look at adding xhci code which might be a better
solution for virtualization.
David
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-04-11 13:23 ` David Ahern
@ 2011-04-11 16:32 ` Jan Kiszka
2011-04-11 16:46 ` Jan Kiszka
1 sibling, 0 replies; 30+ messages in thread
From: Jan Kiszka @ 2011-04-11 16:32 UTC (permalink / raw)
To: David Ahern; +Cc: ya su, Erik Rull, Markus Armbruster, kvm@vger.kernel.org
On 2011-04-11 15:23, David Ahern wrote:
> I lost momentum on the code last August and have not been able to get
> back to it for a variety of reasons. It really needs someone to pick it
> up and continue - or look at adding xhci code which might be a better
> solution for virtualization.
xHCI is on the way [1], but the code was not yet published AFAIK.
Jan
[1]
http://www.linuxtag.org/2011/de/program/freies-vortragsprogramm/popup/vortragsdetails.html?no_cache=1&talkid=103
--
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-04-11 13:23 ` David Ahern
2011-04-11 16:32 ` Jan Kiszka
@ 2011-04-11 16:46 ` Jan Kiszka
2011-04-11 17:53 ` David Ahern
1 sibling, 1 reply; 30+ messages in thread
From: Jan Kiszka @ 2011-04-11 16:46 UTC (permalink / raw)
To: David Ahern; +Cc: ya su, Erik Rull, Markus Armbruster, kvm@vger.kernel.org
On 2011-04-11 15:23, David Ahern wrote:
> I lost momentum on the code last August and have not been able to get
> back to it for a variety of reasons. It really needs someone to pick it
> up and continue - or look at adding xhci code which might be a better
> solution for virtualization.
xHCI is on the way [1], but the code was not yet published AFAIK.
Jan
[1]
http://www.linuxtag.org/2011/de/program/freies-vortragsprogramm/popup/vortragsdetails.html?no_cache=1&talkid=103
--
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-04-11 16:46 ` Jan Kiszka
@ 2011-04-11 17:53 ` David Ahern
2011-04-11 20:07 ` Jan Kiszka
0 siblings, 1 reply; 30+ messages in thread
From: David Ahern @ 2011-04-11 17:53 UTC (permalink / raw)
To: Jan Kiszka; +Cc: ya su, Erik Rull, Markus Armbruster, kvm@vger.kernel.org
On 04/11/11 10:46, Jan Kiszka wrote:
> On 2011-04-11 15:23, David Ahern wrote:
>> I lost momentum on the code last August and have not been able to get
>> back to it for a variety of reasons. It really needs someone to pick it
>> up and continue - or look at adding xhci code which might be a better
>> solution for virtualization.
>
> xHCI is on the way [1], but the code was not yet published AFAIK.
>
> Jan
>
> [1]
> http://www.linuxtag.org/2011/de/program/freies-vortragsprogramm/popup/vortragsdetails.html?no_cache=1&talkid=103
>
interesting. And will it be released / submitted to qemu for inclusion?
David
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-04-11 17:53 ` David Ahern
@ 2011-04-11 20:07 ` Jan Kiszka
2011-04-11 21:10 ` Alexander Graf
0 siblings, 1 reply; 30+ messages in thread
From: Jan Kiszka @ 2011-04-11 20:07 UTC (permalink / raw)
To: David Ahern, Alexander Graf
Cc: ya su, Erik Rull, Markus Armbruster, kvm@vger.kernel.org
[-- Attachment #1: Type: text/plain, Size: 748 bytes --]
On 2011-04-11 19:53, David Ahern wrote:
>
>
> On 04/11/11 10:46, Jan Kiszka wrote:
>> On 2011-04-11 15:23, David Ahern wrote:
>>> I lost momentum on the code last August and have not been able to get
>>> back to it for a variety of reasons. It really needs someone to pick it
>>> up and continue - or look at adding xhci code which might be a better
>>> solution for virtualization.
>>
>> xHCI is on the way [1], but the code was not yet published AFAIK.
>>
>> Jan
>>
>> [1]
>> http://www.linuxtag.org/2011/de/program/freies-vortragsprogramm/popup/vortragsdetails.html?no_cache=1&talkid=103
>>
>
> interesting. And will it be released / submitted to qemu for inclusion?
I suppose so. But maybe Alex can tell more.
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-04-11 20:07 ` Jan Kiszka
@ 2011-04-11 21:10 ` Alexander Graf
0 siblings, 0 replies; 30+ messages in thread
From: Alexander Graf @ 2011-04-11 21:10 UTC (permalink / raw)
To: Jan Kiszka
Cc: David Ahern, ya su, Erik Rull, Markus Armbruster,
kvm@vger.kernel.org list, Feargal Mac Conuladh
On 11.04.2011, at 22:07, Jan Kiszka wrote:
> On 2011-04-11 19:53, David Ahern wrote:
>>
>>
>> On 04/11/11 10:46, Jan Kiszka wrote:
>>> On 2011-04-11 15:23, David Ahern wrote:
>>>> I lost momentum on the code last August and have not been able to get
>>>> back to it for a variety of reasons. It really needs someone to pick it
>>>> up and continue - or look at adding xhci code which might be a better
>>>> solution for virtualization.
>>>
>>> xHCI is on the way [1], but the code was not yet published AFAIK.
>>>
>>> Jan
>>>
>>> [1]
>>> http://www.linuxtag.org/2011/de/program/freies-vortragsprogramm/popup/vortragsdetails.html?no_cache=1&talkid=103
>>>
>>
>> interesting. And will it be released / submitted to qemu for inclusion?
>
> I suppose so. But maybe Alex can tell more.
This is really all in Feargal's hands :).
Alex
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-03-08 18:54 ` David Ahern
@ 2011-06-06 11:33 ` André Weidemann
2011-06-06 13:18 ` David Ahern
0 siblings, 1 reply; 30+ messages in thread
From: André Weidemann @ 2011-06-06 11:33 UTC (permalink / raw)
To: David Ahern; +Cc: kvm@vger.kernel.org
Hi David,
On 08.03.2011 19:54, David Ahern wrote:
>
>
> On 03/08/11 09:23, Erik Rull wrote:
>> Hi all,
>>
>> I've found a usb ehci patch here in the mailing list (begin of january)
>> but it does not fit for 0.14.0.
>
> That was from me and prior work on ehci.
>
>>
>> Is there an updated patch for the latest qemu-kvm version?
>
> Try the attached,
I also wanted to give EHCI support a try. Unfortunately your patch does
not apply to current qemu-kvm git clone. Changes in hw/pc_piix.c and
usb-linux.c make the patch fail. I was able to fix most rejects by hand,
but the last reject in usb-linux.c is beyond my knowledge.
I'd really appreciate if you could find the time to post a patch that
applies to the current git clone.
Thank you very much in advance.
André
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: USB EHCI patch for 0.14.0?
2011-06-06 11:33 ` André Weidemann
@ 2011-06-06 13:18 ` David Ahern
0 siblings, 0 replies; 30+ messages in thread
From: David Ahern @ 2011-06-06 13:18 UTC (permalink / raw)
To: André Weidemann; +Cc: kvm@vger.kernel.org
On 06/06/2011 05:33 AM, André Weidemann wrote:
> I also wanted to give EHCI support a try. Unfortunately your patch does
> not apply to current qemu-kvm git clone. Changes in hw/pc_piix.c and
> usb-linux.c make the patch fail. I was able to fix most rejects by hand,
> but the last reject in usb-linux.c is beyond my knowledge.
> I'd really appreciate if you could find the time to post a patch that
> applies to the current git clone.
>
> Thank you very much in advance.
> André
Looks like the merge of qemu.git into qemu-kvm.git on June 2nd picked up
ehci from qemu. It was committed last week or so. You should not need an
external patch now.
David
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2011-06-06 13:20 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-11 15:18 USB EHCI patch for 0.14.0? erik.rull
2011-03-11 15:39 ` Markus Armbruster
2011-03-11 16:01 ` David Ahern
2011-03-11 16:17 ` Markus Armbruster
2011-03-11 16:34 ` David Ahern
2011-03-11 16:24 ` Erik Rull
2011-03-11 16:46 ` Markus Armbruster
2011-03-11 16:56 ` Erik Rull
2011-03-11 17:11 ` David Ahern
2011-03-11 17:31 ` David Ahern
2011-04-11 9:40 ` ya su
2011-04-11 13:23 ` David Ahern
2011-04-11 16:32 ` Jan Kiszka
2011-04-11 16:46 ` Jan Kiszka
2011-04-11 17:53 ` David Ahern
2011-04-11 20:07 ` Jan Kiszka
2011-04-11 21:10 ` Alexander Graf
2011-03-11 15:57 ` David Ahern
2011-03-11 16:32 ` Erik Rull
-- strict thread matches above, loose matches on Subject: below --
2011-03-14 8:38 erik.rull
2011-03-17 18:05 ` Erik Rull
2011-03-09 15:40 erik.rull
2011-03-09 16:12 ` David Ahern
2011-03-09 21:28 ` Erik Rull
2011-03-09 22:14 ` David Ahern
2011-03-09 22:48 ` Erik Rull
2011-03-08 16:23 Erik Rull
2011-03-08 18:54 ` David Ahern
2011-06-06 11:33 ` André Weidemann
2011-06-06 13:18 ` David Ahern
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox