usb/ehci: split into multiple source files
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
569c7fc840
commit
0bf96f9457
@ -1,6 +1,6 @@
|
|||||||
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
|
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
|
||||||
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
|
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
|
||||||
common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o
|
common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
|
||||||
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
|
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
|
||||||
common-obj-y += libhw.o
|
common-obj-y += libhw.o
|
||||||
|
|
||||||
|
138
hw/usb/hcd-ehci-pci.c
Normal file
138
hw/usb/hcd-ehci-pci.c
Normal file
@ -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)
|
@ -27,31 +27,11 @@
|
|||||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hw/hw.h"
|
#include "hw/usb/hcd-ehci.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
|
|
||||||
|
|
||||||
/* internal processing - reset HC to try and recover */
|
/* internal processing - reset HC to try and recover */
|
||||||
#define USB_RET_PROCERR (-99)
|
#define USB_RET_PROCERR (-99)
|
||||||
|
|
||||||
#define MMIO_SIZE 0x1000
|
|
||||||
#define CAPA_SIZE 0x10
|
|
||||||
|
|
||||||
/* Capability Registers Base Address - section 2.2 */
|
/* Capability Registers Base Address - section 2.2 */
|
||||||
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
||||||
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
|
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
|
||||||
@ -103,9 +83,6 @@
|
|||||||
|
|
||||||
#define CONFIGFLAG 0x0040
|
#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
|
* Bits that are reserved or are read-only are masked out of values
|
||||||
* written to us by software
|
* written to us by software
|
||||||
@ -137,7 +114,6 @@
|
|||||||
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
|
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
|
||||||
|
|
||||||
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
|
#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 BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
|
||||||
#define MAX_QH 100 // Max allowable queue heads in a chain
|
#define MAX_QH 100 // Max allowable queue heads in a chain
|
||||||
#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
|
#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_STITD 2 // split xaction, isoc xfer descriptor
|
||||||
#define NLPTR_TYPE_FSTN 3 // frame span traversal node
|
#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) \
|
#define SET_LAST_RUN_CLOCK(s) \
|
||||||
(s)->last_run_ns = qemu_get_clock_ns(vm_clock);
|
(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,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int usb_ehci_pci_initfn(PCIDevice *dev);
|
|
||||||
|
|
||||||
static USBPortOps ehci_port_ops = {
|
static USBPortOps ehci_port_ops = {
|
||||||
.attach = ehci_attach,
|
.attach = ehci_attach,
|
||||||
.detach = ehci_detach,
|
.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",
|
.name = "ehci-core",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
@ -2655,65 +2350,7 @@ static const VMStateDescription vmstate_ehci = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_ehci_pci = {
|
void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
|
||||||
.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)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -2760,63 +2397,6 @@ static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
|
|||||||
&s->mem_ports);
|
&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
|
* vim: expandtab ts=4
|
||||||
*/
|
*/
|
||||||
|
320
hw/usb/hcd-ehci.h
Normal file
320
hw/usb/hcd-ehci.h
Normal file
@ -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);
|
Loading…
Reference in New Issue
Block a user