aboutsummaryrefslogtreecommitdiff
path: root/hw/usb
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-10-30 12:20:06 +0100
committerGerd Hoffmann <kraxel@redhat.com>2012-11-01 13:10:10 +0100
commit0bf96f9457cdaf620bb8195a971bbdcc732ba32b (patch)
treec9438dd9070c589eda4670874f630148d4f7865e /hw/usb
parent569c7fc8400ea3a7b13589af889003208aaae2ed (diff)
usb/ehci: split into multiple source files
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb')
-rw-r--r--hw/usb/Makefile.objs2
-rw-r--r--hw/usb/hcd-ehci-pci.c138
-rw-r--r--hw/usb/hcd-ehci.c426
-rw-r--r--hw/usb/hcd-ehci.h320
4 files changed, 462 insertions, 424 deletions
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 6425c1ff73..5c7b024103 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -1,6 +1,6 @@
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
-common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o
+common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
common-obj-y += libhw.o
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
new file mode 100644
index 0000000000..daac41d7f8
--- /dev/null
+++ b/hw/usb/hcd-ehci-pci.c
@@ -0,0 +1,138 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * 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 General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/usb/hcd-ehci.h"
+#include "hw/pci.h"
+
+typedef struct EHCIPCIState {
+ PCIDevice pcidev;
+ EHCIState ehci;
+} EHCIPCIState;
+
+static int usb_ehci_pci_initfn(PCIDevice *dev)
+{
+ EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
+ EHCIState *s = &i->ehci;
+ uint8_t *pci_conf = dev->config;
+
+ pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
+
+ /* 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 D */
+ 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[USB_SBRN], USB_RELEASE_2); /* release # (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 */
+
+ s->caps[0x09] = 0x68; /* EECP */
+
+ s->irq = dev->irq[3];
+ s->dma = pci_dma_context(dev);
+
+ s->capsbase = 0x00;
+ s->opregbase = 0x20;
+
+ usb_ehci_initfn(s, DEVICE(dev));
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+
+ return 0;
+}
+
+static Property ehci_pci_properties[] = {
+ DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_ehci_pci = {
+ .name = "ehci",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
+ VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
+ }
+};
+
+static void ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_pci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_pci_properties;
+}
+
+static TypeInfo ehci_info = {
+ .name = "usb-ehci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ehci_class_init,
+};
+
+static void ich9_ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_pci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_pci_properties;
+}
+
+static TypeInfo ich9_ehci_info = {
+ .name = "ich9-usb-ehci1",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ich9_ehci_class_init,
+};
+
+static void ehci_pci_register_types(void)
+{
+ type_register_static(&ehci_info);
+ type_register_static(&ich9_ehci_info);
+}
+
+type_init(ehci_pci_register_types)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index d3168c954d..d9dc576e7c 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -27,31 +27,11 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "hw/hw.h"
-#include "qemu-timer.h"
-#include "hw/usb.h"
-#include "hw/pci.h"
-#include "monitor.h"
-#include "trace.h"
-#include "dma.h"
-#include "sysemu.h"
-
-#ifndef EHCI_DEBUG
-#define EHCI_DEBUG 0
-#endif
-
-#if EHCI_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
+#include "hw/usb/hcd-ehci.h"
/* internal processing - reset HC to try and recover */
#define USB_RET_PROCERR (-99)
-#define MMIO_SIZE 0x1000
-#define CAPA_SIZE 0x10
-
/* Capability Registers Base Address - section 2.2 */
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
@@ -103,9 +83,6 @@
#define CONFIGFLAG 0x0040
-#define PORTSC 0x0044
-#define PORTSC_BEGIN PORTSC
-#define PORTSC_END (PORTSC + 4 * NB_PORTS)
/*
* Bits that are reserved or are read-only are masked out of values
* written to us by software
@@ -137,7 +114,6 @@
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
-#define NB_PORTS 6 // Number of downstream ports
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#define MAX_QH 100 // Max allowable queue heads in a chain
#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
@@ -174,285 +150,6 @@ typedef enum {
#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
-#define ITD_BUFPTR_MULT_SH 0
-} 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
-#define QTD_BUFPTR_SH 12
-} 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 EHCIPacket EHCIPacket;
-typedef struct EHCIQueue EHCIQueue;
-typedef struct EHCIState EHCIState;
-
-enum async_state {
- EHCI_ASYNC_NONE = 0,
- EHCI_ASYNC_INITIALIZED,
- EHCI_ASYNC_INFLIGHT,
- EHCI_ASYNC_FINISHED,
-};
-
-struct EHCIPacket {
- EHCIQueue *queue;
- QTAILQ_ENTRY(EHCIPacket) next;
-
- EHCIqtd qtd; /* copy of current QTD (being worked on) */
- uint32_t qtdaddr; /* address QTD read from */
-
- USBPacket packet;
- QEMUSGList sgl;
- int pid;
- enum async_state async;
- int usb_status;
-};
-
-struct EHCIQueue {
- EHCIState *ehci;
- QTAILQ_ENTRY(EHCIQueue) next;
- uint32_t seen;
- uint64_t ts;
- int async;
- int transact_ctr;
-
- /* 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 */
- uint32_t qtdaddr; /* address QTD read from */
- USBDevice *dev;
- QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
-};
-
-typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
-
-struct EHCIState {
- USBBus bus;
- qemu_irq irq;
- MemoryRegion mem;
- DMAContext *dma;
- MemoryRegion mem_caps;
- MemoryRegion mem_opreg;
- MemoryRegion mem_ports;
- int companion_count;
- uint16_t capsbase;
- uint16_t opregbase;
-
- /* properties */
- uint32_t maxframes;
-
- /*
- * EHCI spec version 1.0 Section 2.3
- * Host Controller Operational Registers
- */
- uint8_t caps[CAPA_SIZE];
- union {
- uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
- struct {
- 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
- */
- QEMUTimer *frame_timer;
- QEMUBH *async_bh;
- uint32_t astate; /* Current state in asynchronous schedule */
- uint32_t pstate; /* Current state in periodic schedule */
- USBPort ports[NB_PORTS];
- USBPort *companion_ports[NB_PORTS];
- uint32_t usbsts_pending;
- uint32_t usbsts_frindex;
- EHCIQueueHead aqueues;
- EHCIQueueHead pqueues;
-
- /* which address to look at next */
- uint32_t a_fetch_addr;
- uint32_t p_fetch_addr;
-
- USBPacket ipacket;
- QEMUSGList isgl;
-
- uint64_t last_run_ns;
- uint32_t async_stepdown;
- bool int_req_by_async;
-};
-
-typedef struct EHCIPCIState {
- PCIDevice pcidev;
- EHCIState ehci;
-} EHCIPCIState;
-
#define SET_LAST_RUN_CLOCK(s) \
(s)->last_run_ns = qemu_get_clock_ns(vm_clock);
@@ -2559,8 +2256,6 @@ static const MemoryRegionOps ehci_mmio_port_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static int usb_ehci_pci_initfn(PCIDevice *dev);
-
static USBPortOps ehci_port_ops = {
.attach = ehci_attach,
.detach = ehci_detach,
@@ -2619,7 +2314,7 @@ static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
}
}
-static const VMStateDescription vmstate_ehci = {
+const VMStateDescription vmstate_ehci = {
.name = "ehci-core",
.version_id = 2,
.minimum_version_id = 1,
@@ -2655,65 +2350,7 @@ static const VMStateDescription vmstate_ehci = {
}
};
-static const VMStateDescription vmstate_ehci_pci = {
- .name = "ehci",
- .version_id = 2,
- .minimum_version_id = 1,
- .post_load = usb_ehci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
- VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
- }
-};
-
-static Property ehci_pci_properties[] = {
- DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ehci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = usb_ehci_pci_initfn;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
- k->revision = 0x10;
- k->class_id = PCI_CLASS_SERIAL_USB;
- dc->vmsd = &vmstate_ehci;
- dc->props = ehci_pci_properties;
-}
-
-static TypeInfo ehci_info = {
- .name = "usb-ehci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EHCIState),
- .class_init = ehci_class_init,
-};
-
-static void ich9_ehci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = usb_ehci_pci_initfn;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
- k->revision = 0x03;
- k->class_id = PCI_CLASS_SERIAL_USB;
- dc->vmsd = &vmstate_ehci;
- dc->props = ehci_pci_properties;
-}
-
-static TypeInfo ich9_ehci_info = {
- .name = "ich9-usb-ehci1",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EHCIState),
- .class_init = ich9_ehci_class_init,
-};
-
-static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
+void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
{
int i;
@@ -2760,63 +2397,6 @@ static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
&s->mem_ports);
}
-static int usb_ehci_pci_initfn(PCIDevice *dev)
-{
- EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
- EHCIState *s = &i->ehci;
- uint8_t *pci_conf = dev->config;
-
- pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-
- /* 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 D */
- 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[USB_SBRN], USB_RELEASE_2); /* release # (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 */
-
- s->caps[0x09] = 0x68; /* EECP */
-
- s->irq = dev->irq[3];
- s->dma = pci_dma_context(dev);
-
- s->capsbase = 0x00;
- s->opregbase = 0x20;
-
- usb_ehci_initfn(s, DEVICE(dev));
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
-
- return 0;
-}
-
-static void ehci_register_types(void)
-{
- type_register_static(&ehci_info);
- type_register_static(&ich9_ehci_info);
-}
-
-type_init(ehci_register_types)
-
/*
* vim: expandtab ts=4
*/
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
new file mode 100644
index 0000000000..0ec675c352
--- /dev/null
+++ b/hw/usb/hcd-ehci.h
@@ -0,0 +1,320 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * 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 General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "hw/usb.h"
+#include "monitor.h"
+#include "trace.h"
+#include "dma.h"
+#include "sysemu.h"
+
+#ifndef EHCI_DEBUG
+#define EHCI_DEBUG 0
+#endif
+
+#if EHCI_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+#define MMIO_SIZE 0x1000
+#define CAPA_SIZE 0x10
+
+#define PORTSC 0x0044
+#define PORTSC_BEGIN PORTSC
+#define PORTSC_END (PORTSC + 4 * NB_PORTS)
+
+#define NB_PORTS 6 /* Number of downstream ports */
+
+typedef struct EHCIPacket EHCIPacket;
+typedef struct EHCIQueue EHCIQueue;
+typedef struct EHCIState EHCIState;
+
+/* 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
+#define ITD_BUFPTR_MULT_SH 0
+} 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
+#define QTD_BUFPTR_SH 12
+} 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;
+
+enum async_state {
+ EHCI_ASYNC_NONE = 0,
+ EHCI_ASYNC_INITIALIZED,
+ EHCI_ASYNC_INFLIGHT,
+ EHCI_ASYNC_FINISHED,
+};
+
+struct EHCIPacket {
+ EHCIQueue *queue;
+ QTAILQ_ENTRY(EHCIPacket) next;
+
+ EHCIqtd qtd; /* copy of current QTD (being worked on) */
+ uint32_t qtdaddr; /* address QTD read from */
+
+ USBPacket packet;
+ QEMUSGList sgl;
+ int pid;
+ enum async_state async;
+ int usb_status;
+};
+
+struct EHCIQueue {
+ EHCIState *ehci;
+ QTAILQ_ENTRY(EHCIQueue) next;
+ uint32_t seen;
+ uint64_t ts;
+ int async;
+ int transact_ctr;
+
+ /* 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 */
+ uint32_t qtdaddr; /* address QTD read from */
+ USBDevice *dev;
+ QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
+};
+
+typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
+
+struct EHCIState {
+ USBBus bus;
+ qemu_irq irq;
+ MemoryRegion mem;
+ DMAContext *dma;
+ MemoryRegion mem_caps;
+ MemoryRegion mem_opreg;
+ MemoryRegion mem_ports;
+ int companion_count;
+ uint16_t capsbase;
+ uint16_t opregbase;
+
+ /* properties */
+ uint32_t maxframes;
+
+ /*
+ * EHCI spec version 1.0 Section 2.3
+ * Host Controller Operational Registers
+ */
+ uint8_t caps[CAPA_SIZE];
+ union {
+ uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
+ struct {
+ 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
+ */
+ QEMUTimer *frame_timer;
+ QEMUBH *async_bh;
+ uint32_t astate; /* Current state in asynchronous schedule */
+ uint32_t pstate; /* Current state in periodic schedule */
+ USBPort ports[NB_PORTS];
+ USBPort *companion_ports[NB_PORTS];
+ uint32_t usbsts_pending;
+ uint32_t usbsts_frindex;
+ EHCIQueueHead aqueues;
+ EHCIQueueHead pqueues;
+
+ /* which address to look at next */
+ uint32_t a_fetch_addr;
+ uint32_t p_fetch_addr;
+
+ USBPacket ipacket;
+ QEMUSGList isgl;
+
+ uint64_t last_run_ns;
+ uint32_t async_stepdown;
+ bool int_req_by_async;
+};
+
+extern const VMStateDescription vmstate_ehci;
+
+void usb_ehci_initfn(EHCIState *s, DeviceState *dev);