123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- /*
- * 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/>.
- */
- #ifndef HW_USB_EHCI_H
- #define HW_USB_EHCI_H 1
- #include "hw/hw.h"
- #include "qemu/timer.h"
- #include "hw/usb.h"
- #include "monitor/monitor.h"
- #include "trace.h"
- #include "sysemu/dma.h"
- #include "sysemu/sysemu.h"
- #include "hw/pci/pci.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 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;
- };
- 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(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;
- uint32_t periodic_sched_active;
- bool int_req_by_async;
- };
- extern const VMStateDescription vmstate_ehci;
- void usb_ehci_initfn(EHCIState *s, DeviceState *dev);
- #define TYPE_PCI_EHCI "pci-ehci-usb"
- #define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI)
- typedef struct EHCIPCIState {
- /*< private >*/
- PCIDevice pcidev;
- /*< public >*/
- EHCIState ehci;
- } EHCIPCIState;
- #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
- #define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
- #define SYS_BUS_EHCI(obj) \
- OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI)
- #define SYS_BUS_EHCI_CLASS(class) \
- OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI)
- #define SYS_BUS_EHCI_GET_CLASS(obj) \
- OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI)
- typedef struct EHCISysBusState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
- EHCIState ehci;
- } EHCISysBusState;
- typedef struct SysBusEHCIClass {
- /*< private >*/
- SysBusDeviceClass parent_class;
- /*< public >*/
- uint16_t capsbase;
- uint16_t opregbase;
- } SysBusEHCIClass;
- #endif
|