|  | /* | 
|  | * 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.1 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 program; if not, see <http://www.gnu.org/licenses/>. | 
|  | */ | 
|  |  | 
|  | #ifndef HW_USB_HCD_EHCI_H | 
|  | #define HW_USB_HCD_EHCI_H | 
|  |  | 
|  | #include "qemu/timer.h" | 
|  | #include "hw/usb.h" | 
|  | #include "sysemu/dma.h" | 
|  | #include "hw/pci/pci_device.h" | 
|  | #include "hw/sysbus.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 EHCI_PORTS       6        /* Max. 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; | 
|  | }; | 
|  |  | 
|  | 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                */ | 
|  | int last_pid;          /* pid of last packet executed          */ | 
|  | USBDevice *dev; | 
|  | QTAILQ_HEAD(, EHCIPacket) packets; | 
|  | }; | 
|  |  | 
|  | typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; | 
|  |  | 
|  | struct EHCIState { | 
|  | USBBus bus; | 
|  | DeviceState *device; | 
|  | qemu_irq irq; | 
|  | MemoryRegion mem; | 
|  | AddressSpace *as; | 
|  | MemoryRegion mem_caps; | 
|  | MemoryRegion mem_opreg; | 
|  | MemoryRegion mem_ports; | 
|  | int companion_count; | 
|  | bool companion_enable; | 
|  | uint16_t capsbase; | 
|  | uint16_t opregbase; | 
|  | uint16_t portscbase; | 
|  | uint16_t portnr; | 
|  |  | 
|  | /* 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[0x44/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[EHCI_PORTS]; | 
|  |  | 
|  | /* | 
|  | *  Internal states, shadow registers, etc | 
|  | */ | 
|  | QEMUTimer *frame_timer; | 
|  | QEMUBH *async_bh; | 
|  | bool working; | 
|  | uint32_t astate;         /* Current state in asynchronous schedule */ | 
|  | uint32_t pstate;         /* Current state in periodic schedule     */ | 
|  | USBPort ports[EHCI_PORTS]; | 
|  | USBPort *companion_ports[EHCI_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; | 
|  | uint32_t periodic_sched_active; | 
|  | bool int_req_by_async; | 
|  | VMChangeStateEntry *vmstate; | 
|  | }; | 
|  |  | 
|  | extern const VMStateDescription vmstate_ehci; | 
|  |  | 
|  | void usb_ehci_init(EHCIState *s, DeviceState *dev); | 
|  | void usb_ehci_finalize(EHCIState *s); | 
|  | void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp); | 
|  | void usb_ehci_unrealize(EHCIState *s, DeviceState *dev); | 
|  | void ehci_reset(void *opaque); | 
|  |  | 
|  | #define TYPE_PCI_EHCI "pci-ehci-usb" | 
|  | OBJECT_DECLARE_SIMPLE_TYPE(EHCIPCIState, PCI_EHCI) | 
|  |  | 
|  | struct EHCIPCIState { | 
|  | /*< private >*/ | 
|  | PCIDevice pcidev; | 
|  | /*< public >*/ | 
|  |  | 
|  | EHCIState ehci; | 
|  | }; | 
|  |  | 
|  |  | 
|  | #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" | 
|  | #define TYPE_PLATFORM_EHCI "platform-ehci-usb" | 
|  | #define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb" | 
|  | #define TYPE_AW_H3_EHCI "aw-h3-ehci-usb" | 
|  | #define TYPE_NPCM7XX_EHCI "npcm7xx-ehci-usb" | 
|  | #define TYPE_TEGRA2_EHCI "tegra2-ehci-usb" | 
|  | #define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb" | 
|  | #define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb" | 
|  |  | 
|  | OBJECT_DECLARE_TYPE(EHCISysBusState, SysBusEHCIClass, SYS_BUS_EHCI) | 
|  |  | 
|  | struct EHCISysBusState { | 
|  | /*< private >*/ | 
|  | SysBusDevice parent_obj; | 
|  | /*< public >*/ | 
|  |  | 
|  | EHCIState ehci; | 
|  | }; | 
|  |  | 
|  | struct SysBusEHCIClass { | 
|  | /*< private >*/ | 
|  | SysBusDeviceClass parent_class; | 
|  | /*< public >*/ | 
|  |  | 
|  | uint16_t capsbase; | 
|  | uint16_t opregbase; | 
|  | uint16_t portscbase; | 
|  | uint16_t portnr; | 
|  | }; | 
|  |  | 
|  | OBJECT_DECLARE_SIMPLE_TYPE(FUSBH200EHCIState, FUSBH200_EHCI) | 
|  |  | 
|  | struct FUSBH200EHCIState { | 
|  | /*< private >*/ | 
|  | EHCISysBusState parent_obj; | 
|  | /*< public >*/ | 
|  |  | 
|  | MemoryRegion mem_vendor; | 
|  | }; | 
|  |  | 
|  | #endif |