1f1ae32a1SGerd Hoffmann /* 2f1ae32a1SGerd Hoffmann * QEMU USB OHCI Emulation 3f1ae32a1SGerd Hoffmann * Copyright (c) 2004 Gianni Tedesco 4f1ae32a1SGerd Hoffmann * Copyright (c) 2006 CodeSourcery 5f1ae32a1SGerd Hoffmann * Copyright (c) 2006 Openedhand Ltd. 6f1ae32a1SGerd Hoffmann * 7f1ae32a1SGerd Hoffmann * This library is free software; you can redistribute it and/or 8f1ae32a1SGerd Hoffmann * modify it under the terms of the GNU Lesser General Public 9f1ae32a1SGerd Hoffmann * License as published by the Free Software Foundation; either 10f1ae32a1SGerd Hoffmann * version 2 of the License, or (at your option) any later version. 11f1ae32a1SGerd Hoffmann * 12f1ae32a1SGerd Hoffmann * This library is distributed in the hope that it will be useful, 13f1ae32a1SGerd Hoffmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 14f1ae32a1SGerd Hoffmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15f1ae32a1SGerd Hoffmann * Lesser General Public License for more details. 16f1ae32a1SGerd Hoffmann * 17f1ae32a1SGerd Hoffmann * You should have received a copy of the GNU Lesser General Public 18f1ae32a1SGerd Hoffmann * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19f1ae32a1SGerd Hoffmann * 20f1ae32a1SGerd Hoffmann * TODO: 21f1ae32a1SGerd Hoffmann * o Isochronous transfers 22f1ae32a1SGerd Hoffmann * o Allocate bandwidth in frames properly 23f1ae32a1SGerd Hoffmann * o Disable timers when nothing needs to be done, or remove timer usage 24f1ae32a1SGerd Hoffmann * all together. 25f1ae32a1SGerd Hoffmann * o BIOS work to boot from USB storage 26f1ae32a1SGerd Hoffmann */ 27f1ae32a1SGerd Hoffmann 28e532b2e0SPeter Maydell #include "qemu/osdep.h" 29f1ae32a1SGerd Hoffmann #include "hw/hw.h" 30da34e65cSMarkus Armbruster #include "qapi/error.h" 31*0b8fa32fSMarkus Armbruster #include "qemu/module.h" 321de7afc9SPaolo Bonzini #include "qemu/timer.h" 33f1ae32a1SGerd Hoffmann #include "hw/usb.h" 34f1ae32a1SGerd Hoffmann #include "hw/sysbus.h" 359ac6a217SDavid Gibson #include "hw/qdev-dma.h" 36dc1f5988SAlexey Kardashevskiy #include "trace.h" 3734d97308SThomas Huth #include "hcd-ohci.h" 38f1ae32a1SGerd Hoffmann 39f1ae32a1SGerd Hoffmann /* This causes frames to occur 1000x slower */ 40f1ae32a1SGerd Hoffmann //#define OHCI_TIME_WARP 1 41f1ae32a1SGerd Hoffmann 42ab6b1105SGerd Hoffmann #define ED_LINK_LIMIT 32 4395ed5693SLi Qiang 44f1ae32a1SGerd Hoffmann static int64_t usb_frame_time; 45f1ae32a1SGerd Hoffmann static int64_t usb_bit_time; 46f1ae32a1SGerd Hoffmann 47f1ae32a1SGerd Hoffmann /* Host Controller Communications Area */ 48f1ae32a1SGerd Hoffmann struct ohci_hcca { 49f1ae32a1SGerd Hoffmann uint32_t intr[32]; 50f1ae32a1SGerd Hoffmann uint16_t frame, pad; 51f1ae32a1SGerd Hoffmann uint32_t done; 52f1ae32a1SGerd Hoffmann }; 5386e18caeSWei Yang #define HCCA_WRITEBACK_OFFSET offsetof(struct ohci_hcca, frame) 5486e18caeSWei Yang #define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */ 5586e18caeSWei Yang 5686e18caeSWei Yang #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head) 5786e18caeSWei Yang #define ED_WBACK_SIZE 4 58f1ae32a1SGerd Hoffmann 59f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); 60f1ae32a1SGerd Hoffmann 61f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Endpoint Desciptor. */ 62f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_SHIFT 0 63f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT) 64f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_SHIFT 7 65f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT) 66f1ae32a1SGerd Hoffmann #define OHCI_ED_D_SHIFT 11 67f1ae32a1SGerd Hoffmann #define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT) 68f1ae32a1SGerd Hoffmann #define OHCI_ED_S (1<<13) 69f1ae32a1SGerd Hoffmann #define OHCI_ED_K (1<<14) 70f1ae32a1SGerd Hoffmann #define OHCI_ED_F (1<<15) 71f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_SHIFT 16 72f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_MASK (0x7ff<<OHCI_ED_MPS_SHIFT) 73f1ae32a1SGerd Hoffmann 74f1ae32a1SGerd Hoffmann /* Flags in the head field of an Endpoint Desciptor. */ 75f1ae32a1SGerd Hoffmann #define OHCI_ED_H 1 76f1ae32a1SGerd Hoffmann #define OHCI_ED_C 2 77f1ae32a1SGerd Hoffmann 78f1ae32a1SGerd Hoffmann /* Bitfields for the first word of a Transfer Desciptor. */ 79f1ae32a1SGerd Hoffmann #define OHCI_TD_R (1<<18) 80f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_SHIFT 19 81f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT) 82f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_SHIFT 21 83f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT) 84f1ae32a1SGerd Hoffmann #define OHCI_TD_T0 (1<<24) 85f1ae32a1SGerd Hoffmann #define OHCI_TD_T1 (1<<25) 86f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_SHIFT 26 87f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT) 88f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_SHIFT 28 89f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT) 90f1ae32a1SGerd Hoffmann 91f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Isochronous Transfer Desciptor. */ 92f1ae32a1SGerd Hoffmann /* CC & DI - same as in the General Transfer Desciptor */ 93f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_SHIFT 0 94f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT) 95f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_SHIFT 24 96f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT) 97f1ae32a1SGerd Hoffmann 98f1ae32a1SGerd Hoffmann /* Isochronous Transfer Desciptor - Offset / PacketStatusWord */ 99f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_SHIFT 12 100f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT) 101f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_SHIFT 0 102f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT) 103f1ae32a1SGerd Hoffmann 104f1ae32a1SGerd Hoffmann #define OHCI_PAGE_MASK 0xfffff000 105f1ae32a1SGerd Hoffmann #define OHCI_OFFSET_MASK 0xfff 106f1ae32a1SGerd Hoffmann 107f1ae32a1SGerd Hoffmann #define OHCI_DPTR_MASK 0xfffffff0 108f1ae32a1SGerd Hoffmann 109f1ae32a1SGerd Hoffmann #define OHCI_BM(val, field) \ 110f1ae32a1SGerd Hoffmann (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT) 111f1ae32a1SGerd Hoffmann 112f1ae32a1SGerd Hoffmann #define OHCI_SET_BM(val, field, newval) do { \ 113f1ae32a1SGerd Hoffmann val &= ~OHCI_##field##_MASK; \ 114f1ae32a1SGerd Hoffmann val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ 115f1ae32a1SGerd Hoffmann } while(0) 116f1ae32a1SGerd Hoffmann 117f1ae32a1SGerd Hoffmann /* endpoint descriptor */ 118f1ae32a1SGerd Hoffmann struct ohci_ed { 119f1ae32a1SGerd Hoffmann uint32_t flags; 120f1ae32a1SGerd Hoffmann uint32_t tail; 121f1ae32a1SGerd Hoffmann uint32_t head; 122f1ae32a1SGerd Hoffmann uint32_t next; 123f1ae32a1SGerd Hoffmann }; 124f1ae32a1SGerd Hoffmann 125f1ae32a1SGerd Hoffmann /* General transfer descriptor */ 126f1ae32a1SGerd Hoffmann struct ohci_td { 127f1ae32a1SGerd Hoffmann uint32_t flags; 128f1ae32a1SGerd Hoffmann uint32_t cbp; 129f1ae32a1SGerd Hoffmann uint32_t next; 130f1ae32a1SGerd Hoffmann uint32_t be; 131f1ae32a1SGerd Hoffmann }; 132f1ae32a1SGerd Hoffmann 133f1ae32a1SGerd Hoffmann /* Isochronous transfer descriptor */ 134f1ae32a1SGerd Hoffmann struct ohci_iso_td { 135f1ae32a1SGerd Hoffmann uint32_t flags; 136f1ae32a1SGerd Hoffmann uint32_t bp; 137f1ae32a1SGerd Hoffmann uint32_t next; 138f1ae32a1SGerd Hoffmann uint32_t be; 139f1ae32a1SGerd Hoffmann uint16_t offset[8]; 140f1ae32a1SGerd Hoffmann }; 141f1ae32a1SGerd Hoffmann 142f1ae32a1SGerd Hoffmann #define USB_HZ 12000000 143f1ae32a1SGerd Hoffmann 144f1ae32a1SGerd Hoffmann /* OHCI Local stuff */ 145f1ae32a1SGerd Hoffmann #define OHCI_CTL_CBSR ((1<<0)|(1<<1)) 146f1ae32a1SGerd Hoffmann #define OHCI_CTL_PLE (1<<2) 147f1ae32a1SGerd Hoffmann #define OHCI_CTL_IE (1<<3) 148f1ae32a1SGerd Hoffmann #define OHCI_CTL_CLE (1<<4) 149f1ae32a1SGerd Hoffmann #define OHCI_CTL_BLE (1<<5) 150f1ae32a1SGerd Hoffmann #define OHCI_CTL_HCFS ((1<<6)|(1<<7)) 151f1ae32a1SGerd Hoffmann #define OHCI_USB_RESET 0x00 152f1ae32a1SGerd Hoffmann #define OHCI_USB_RESUME 0x40 153f1ae32a1SGerd Hoffmann #define OHCI_USB_OPERATIONAL 0x80 154f1ae32a1SGerd Hoffmann #define OHCI_USB_SUSPEND 0xc0 155f1ae32a1SGerd Hoffmann #define OHCI_CTL_IR (1<<8) 156f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWC (1<<9) 157f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWE (1<<10) 158f1ae32a1SGerd Hoffmann 159f1ae32a1SGerd Hoffmann #define OHCI_STATUS_HCR (1<<0) 160f1ae32a1SGerd Hoffmann #define OHCI_STATUS_CLF (1<<1) 161f1ae32a1SGerd Hoffmann #define OHCI_STATUS_BLF (1<<2) 162f1ae32a1SGerd Hoffmann #define OHCI_STATUS_OCR (1<<3) 163f1ae32a1SGerd Hoffmann #define OHCI_STATUS_SOC ((1<<6)|(1<<7)) 164f1ae32a1SGerd Hoffmann 16500b01793SPeter Maydell #define OHCI_INTR_SO (1U<<0) /* Scheduling overrun */ 16600b01793SPeter Maydell #define OHCI_INTR_WD (1U<<1) /* HcDoneHead writeback */ 16700b01793SPeter Maydell #define OHCI_INTR_SF (1U<<2) /* Start of frame */ 16800b01793SPeter Maydell #define OHCI_INTR_RD (1U<<3) /* Resume detect */ 16900b01793SPeter Maydell #define OHCI_INTR_UE (1U<<4) /* Unrecoverable error */ 17000b01793SPeter Maydell #define OHCI_INTR_FNO (1U<<5) /* Frame number overflow */ 17100b01793SPeter Maydell #define OHCI_INTR_RHSC (1U<<6) /* Root hub status change */ 17200b01793SPeter Maydell #define OHCI_INTR_OC (1U<<30) /* Ownership change */ 17300b01793SPeter Maydell #define OHCI_INTR_MIE (1U<<31) /* Master Interrupt Enable */ 174f1ae32a1SGerd Hoffmann 175f1ae32a1SGerd Hoffmann #define OHCI_HCCA_SIZE 0x100 176f1ae32a1SGerd Hoffmann #define OHCI_HCCA_MASK 0xffffff00 177f1ae32a1SGerd Hoffmann 178f1ae32a1SGerd Hoffmann #define OHCI_EDPTR_MASK 0xfffffff0 179f1ae32a1SGerd Hoffmann 180f1ae32a1SGerd Hoffmann #define OHCI_FMI_FI 0x00003fff 181f1ae32a1SGerd Hoffmann #define OHCI_FMI_FSMPS 0xffff0000 182f1ae32a1SGerd Hoffmann #define OHCI_FMI_FIT 0x80000000 183f1ae32a1SGerd Hoffmann 18400b01793SPeter Maydell #define OHCI_FR_RT (1U<<31) 185f1ae32a1SGerd Hoffmann 186f1ae32a1SGerd Hoffmann #define OHCI_LS_THRESH 0x628 187f1ae32a1SGerd Hoffmann 188f1ae32a1SGerd Hoffmann #define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ 189f1ae32a1SGerd Hoffmann #define OHCI_RHA_PSM (1<<8) 190f1ae32a1SGerd Hoffmann #define OHCI_RHA_NPS (1<<9) 191f1ae32a1SGerd Hoffmann #define OHCI_RHA_DT (1<<10) 192f1ae32a1SGerd Hoffmann #define OHCI_RHA_OCPM (1<<11) 193f1ae32a1SGerd Hoffmann #define OHCI_RHA_NOCP (1<<12) 194f1ae32a1SGerd Hoffmann #define OHCI_RHA_POTPGT_MASK 0xff000000 195f1ae32a1SGerd Hoffmann 19600b01793SPeter Maydell #define OHCI_RHS_LPS (1U<<0) 19700b01793SPeter Maydell #define OHCI_RHS_OCI (1U<<1) 19800b01793SPeter Maydell #define OHCI_RHS_DRWE (1U<<15) 19900b01793SPeter Maydell #define OHCI_RHS_LPSC (1U<<16) 20000b01793SPeter Maydell #define OHCI_RHS_OCIC (1U<<17) 20100b01793SPeter Maydell #define OHCI_RHS_CRWE (1U<<31) 202f1ae32a1SGerd Hoffmann 203f1ae32a1SGerd Hoffmann #define OHCI_PORT_CCS (1<<0) 204f1ae32a1SGerd Hoffmann #define OHCI_PORT_PES (1<<1) 205f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSS (1<<2) 206f1ae32a1SGerd Hoffmann #define OHCI_PORT_POCI (1<<3) 207f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRS (1<<4) 208f1ae32a1SGerd Hoffmann #define OHCI_PORT_PPS (1<<8) 209f1ae32a1SGerd Hoffmann #define OHCI_PORT_LSDA (1<<9) 210f1ae32a1SGerd Hoffmann #define OHCI_PORT_CSC (1<<16) 211f1ae32a1SGerd Hoffmann #define OHCI_PORT_PESC (1<<17) 212f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSSC (1<<18) 213f1ae32a1SGerd Hoffmann #define OHCI_PORT_OCIC (1<<19) 214f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRSC (1<<20) 215f1ae32a1SGerd Hoffmann #define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ 216f1ae32a1SGerd Hoffmann |OHCI_PORT_OCIC|OHCI_PORT_PRSC) 217f1ae32a1SGerd Hoffmann 218f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_SETUP 0x0 219f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_OUT 0x1 220f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_IN 0x2 221f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_RESERVED 0x3 222f1ae32a1SGerd Hoffmann 223f1ae32a1SGerd Hoffmann #define OHCI_CC_NOERROR 0x0 224f1ae32a1SGerd Hoffmann #define OHCI_CC_CRC 0x1 225f1ae32a1SGerd Hoffmann #define OHCI_CC_BITSTUFFING 0x2 226f1ae32a1SGerd Hoffmann #define OHCI_CC_DATATOGGLEMISMATCH 0x3 227f1ae32a1SGerd Hoffmann #define OHCI_CC_STALL 0x4 228f1ae32a1SGerd Hoffmann #define OHCI_CC_DEVICENOTRESPONDING 0x5 229f1ae32a1SGerd Hoffmann #define OHCI_CC_PIDCHECKFAILURE 0x6 230f1ae32a1SGerd Hoffmann #define OHCI_CC_UNDEXPETEDPID 0x7 231f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAOVERRUN 0x8 232f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAUNDERRUN 0x9 233f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFEROVERRUN 0xc 234f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFERUNDERRUN 0xd 235f1ae32a1SGerd Hoffmann 236f1ae32a1SGerd Hoffmann #define OHCI_HRESET_FSBIR (1 << 0) 237f1ae32a1SGerd Hoffmann 23872e0c127SThomas Huth static void ohci_die(OHCIState *ohci) 23972e0c127SThomas Huth { 24072e0c127SThomas Huth ohci->ohci_die(ohci); 24172e0c127SThomas Huth } 242cf66ee8eSAlexey Kardashevskiy 243f1ae32a1SGerd Hoffmann /* Update IRQ levels */ 244f1ae32a1SGerd Hoffmann static inline void ohci_intr_update(OHCIState *ohci) 245f1ae32a1SGerd Hoffmann { 246f1ae32a1SGerd Hoffmann int level = 0; 247f1ae32a1SGerd Hoffmann 248f1ae32a1SGerd Hoffmann if ((ohci->intr & OHCI_INTR_MIE) && 249f1ae32a1SGerd Hoffmann (ohci->intr_status & ohci->intr)) 250f1ae32a1SGerd Hoffmann level = 1; 251f1ae32a1SGerd Hoffmann 252f1ae32a1SGerd Hoffmann qemu_set_irq(ohci->irq, level); 253f1ae32a1SGerd Hoffmann } 254f1ae32a1SGerd Hoffmann 255f1ae32a1SGerd Hoffmann /* Set an interrupt */ 256f1ae32a1SGerd Hoffmann static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) 257f1ae32a1SGerd Hoffmann { 258f1ae32a1SGerd Hoffmann ohci->intr_status |= intr; 259f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 260f1ae32a1SGerd Hoffmann } 261f1ae32a1SGerd Hoffmann 262f1ae32a1SGerd Hoffmann /* Attach or detach a device on a root hub port. */ 263f1ae32a1SGerd Hoffmann static void ohci_attach(USBPort *port1) 264f1ae32a1SGerd Hoffmann { 265f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 266f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 267f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 268f1ae32a1SGerd Hoffmann 269f1ae32a1SGerd Hoffmann /* set connect status */ 270f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; 271f1ae32a1SGerd Hoffmann 272f1ae32a1SGerd Hoffmann /* update speed */ 273f1ae32a1SGerd Hoffmann if (port->port.dev->speed == USB_SPEED_LOW) { 274f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_LSDA; 275f1ae32a1SGerd Hoffmann } else { 276f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_LSDA; 277f1ae32a1SGerd Hoffmann } 278f1ae32a1SGerd Hoffmann 279f1ae32a1SGerd Hoffmann /* notify of remote-wakeup */ 280f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 281f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RD); 282f1ae32a1SGerd Hoffmann } 283f1ae32a1SGerd Hoffmann 284dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_attach(port1->index); 285f1ae32a1SGerd Hoffmann 286f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 287f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 288f1ae32a1SGerd Hoffmann } 289f1ae32a1SGerd Hoffmann } 290f1ae32a1SGerd Hoffmann 291f1ae32a1SGerd Hoffmann static void ohci_detach(USBPort *port1) 292f1ae32a1SGerd Hoffmann { 293f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 294f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 295f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 296f1ae32a1SGerd Hoffmann 297f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, port1->dev); 298f1ae32a1SGerd Hoffmann 299f1ae32a1SGerd Hoffmann /* set connect status */ 300f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_CCS) { 301f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_CCS; 302f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CSC; 303f1ae32a1SGerd Hoffmann } 304f1ae32a1SGerd Hoffmann /* disable port */ 305f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PES) { 306f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 307f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PESC; 308f1ae32a1SGerd Hoffmann } 309dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_detach(port1->index); 310f1ae32a1SGerd Hoffmann 311f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 312f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 313f1ae32a1SGerd Hoffmann } 314f1ae32a1SGerd Hoffmann } 315f1ae32a1SGerd Hoffmann 316f1ae32a1SGerd Hoffmann static void ohci_wakeup(USBPort *port1) 317f1ae32a1SGerd Hoffmann { 318f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 319f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 320f1ae32a1SGerd Hoffmann uint32_t intr = 0; 321f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PSS) { 322dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_wakeup(port1->index); 323f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PSSC; 324f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PSS; 325f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RHSC; 326f1ae32a1SGerd Hoffmann } 327f1ae32a1SGerd Hoffmann /* Note that the controller can be suspended even if this port is not */ 328f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 329dc1f5988SAlexey Kardashevskiy trace_usb_ohci_remote_wakeup(s->name); 330f1ae32a1SGerd Hoffmann /* This is the one state transition the controller can do by itself */ 331f1ae32a1SGerd Hoffmann s->ctl &= ~OHCI_CTL_HCFS; 332f1ae32a1SGerd Hoffmann s->ctl |= OHCI_USB_RESUME; 333f1ae32a1SGerd Hoffmann /* In suspend mode only ResumeDetected is possible, not RHSC: 334f1ae32a1SGerd Hoffmann * see the OHCI spec 5.1.2.3. 335f1ae32a1SGerd Hoffmann */ 336f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RD; 337f1ae32a1SGerd Hoffmann } 338f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, intr); 339f1ae32a1SGerd Hoffmann } 340f1ae32a1SGerd Hoffmann 341f1ae32a1SGerd Hoffmann static void ohci_child_detach(USBPort *port1, USBDevice *child) 342f1ae32a1SGerd Hoffmann { 343f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 344f1ae32a1SGerd Hoffmann 345f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, child); 346f1ae32a1SGerd Hoffmann } 347f1ae32a1SGerd Hoffmann 348f1ae32a1SGerd Hoffmann static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr) 349f1ae32a1SGerd Hoffmann { 350f1ae32a1SGerd Hoffmann USBDevice *dev; 351f1ae32a1SGerd Hoffmann int i; 352f1ae32a1SGerd Hoffmann 353f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) { 354f1ae32a1SGerd Hoffmann if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) { 355f1ae32a1SGerd Hoffmann continue; 356f1ae32a1SGerd Hoffmann } 357f1ae32a1SGerd Hoffmann dev = usb_find_device(&ohci->rhport[i].port, addr); 358f1ae32a1SGerd Hoffmann if (dev != NULL) { 359f1ae32a1SGerd Hoffmann return dev; 360f1ae32a1SGerd Hoffmann } 361f1ae32a1SGerd Hoffmann } 362f1ae32a1SGerd Hoffmann return NULL; 363f1ae32a1SGerd Hoffmann } 364f1ae32a1SGerd Hoffmann 36534d97308SThomas Huth void ohci_stop_endpoints(OHCIState *ohci) 366f79738b0SHans de Goede { 367f79738b0SHans de Goede USBDevice *dev; 368f79738b0SHans de Goede int i, j; 369f79738b0SHans de Goede 370f79738b0SHans de Goede for (i = 0; i < ohci->num_ports; i++) { 371f79738b0SHans de Goede dev = ohci->rhport[i].port.dev; 372f79738b0SHans de Goede if (dev && dev->attached) { 373f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_ctl); 374f79738b0SHans de Goede for (j = 0; j < USB_MAX_ENDPOINTS; j++) { 375f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_in[j]); 376f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_out[j]); 377f79738b0SHans de Goede } 378f79738b0SHans de Goede } 379f79738b0SHans de Goede } 380f79738b0SHans de Goede } 381f79738b0SHans de Goede 38284d04e21SHervé Poussineau static void ohci_roothub_reset(OHCIState *ohci) 383f1ae32a1SGerd Hoffmann { 384f1ae32a1SGerd Hoffmann OHCIPort *port; 385f1ae32a1SGerd Hoffmann int i; 386f1ae32a1SGerd Hoffmann 387f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 38884d04e21SHervé Poussineau ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; 38984d04e21SHervé Poussineau ohci->rhdesc_b = 0x0; /* Impl. specific */ 39084d04e21SHervé Poussineau ohci->rhstatus = 0; 39184d04e21SHervé Poussineau 39284d04e21SHervé Poussineau for (i = 0; i < ohci->num_ports; i++) { 39384d04e21SHervé Poussineau port = &ohci->rhport[i]; 39484d04e21SHervé Poussineau port->ctrl = 0; 39584d04e21SHervé Poussineau if (port->port.dev && port->port.dev->attached) { 39684d04e21SHervé Poussineau usb_port_reset(&port->port); 39784d04e21SHervé Poussineau } 39884d04e21SHervé Poussineau } 39984d04e21SHervé Poussineau if (ohci->async_td) { 40084d04e21SHervé Poussineau usb_cancel_packet(&ohci->usb_packet); 40184d04e21SHervé Poussineau ohci->async_td = 0; 40284d04e21SHervé Poussineau } 40384d04e21SHervé Poussineau ohci_stop_endpoints(ohci); 40484d04e21SHervé Poussineau } 40584d04e21SHervé Poussineau 40684d04e21SHervé Poussineau /* Reset the controller */ 40784d04e21SHervé Poussineau static void ohci_soft_reset(OHCIState *ohci) 40884d04e21SHervé Poussineau { 40984d04e21SHervé Poussineau trace_usb_ohci_reset(ohci->name); 41084d04e21SHervé Poussineau 41184d04e21SHervé Poussineau ohci_bus_stop(ohci); 41284d04e21SHervé Poussineau ohci->ctl = (ohci->ctl & OHCI_CTL_IR) | OHCI_USB_SUSPEND; 413f1ae32a1SGerd Hoffmann ohci->old_ctl = 0; 414f1ae32a1SGerd Hoffmann ohci->status = 0; 415f1ae32a1SGerd Hoffmann ohci->intr_status = 0; 416f1ae32a1SGerd Hoffmann ohci->intr = OHCI_INTR_MIE; 417f1ae32a1SGerd Hoffmann 418f1ae32a1SGerd Hoffmann ohci->hcca = 0; 419f1ae32a1SGerd Hoffmann ohci->ctrl_head = ohci->ctrl_cur = 0; 420f1ae32a1SGerd Hoffmann ohci->bulk_head = ohci->bulk_cur = 0; 421f1ae32a1SGerd Hoffmann ohci->per_cur = 0; 422f1ae32a1SGerd Hoffmann ohci->done = 0; 423f1ae32a1SGerd Hoffmann ohci->done_count = 7; 424f1ae32a1SGerd Hoffmann 425f1ae32a1SGerd Hoffmann /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? 426f1ae32a1SGerd Hoffmann * I took the value linux sets ... 427f1ae32a1SGerd Hoffmann */ 428f1ae32a1SGerd Hoffmann ohci->fsmps = 0x2778; 429f1ae32a1SGerd Hoffmann ohci->fi = 0x2edf; 430f1ae32a1SGerd Hoffmann ohci->fit = 0; 431f1ae32a1SGerd Hoffmann ohci->frt = 0; 432f1ae32a1SGerd Hoffmann ohci->frame_number = 0; 433f1ae32a1SGerd Hoffmann ohci->pstart = 0; 434f1ae32a1SGerd Hoffmann ohci->lst = OHCI_LS_THRESH; 43584d04e21SHervé Poussineau } 436f1ae32a1SGerd Hoffmann 43734d97308SThomas Huth void ohci_hard_reset(OHCIState *ohci) 438f1ae32a1SGerd Hoffmann { 43984d04e21SHervé Poussineau ohci_soft_reset(ohci); 44084d04e21SHervé Poussineau ohci->ctl = 0; 44184d04e21SHervé Poussineau ohci_roothub_reset(ohci); 442f1ae32a1SGerd Hoffmann } 443f1ae32a1SGerd Hoffmann 444f1ae32a1SGerd Hoffmann /* Get an array of dwords from main memory */ 445f1ae32a1SGerd Hoffmann static inline int get_dwords(OHCIState *ohci, 4469ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 447f1ae32a1SGerd Hoffmann { 448f1ae32a1SGerd Hoffmann int i; 449f1ae32a1SGerd Hoffmann 450f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 451f1ae32a1SGerd Hoffmann 452f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 453cf66ee8eSAlexey Kardashevskiy if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { 454cf66ee8eSAlexey Kardashevskiy return -1; 455cf66ee8eSAlexey Kardashevskiy } 456f1ae32a1SGerd Hoffmann *buf = le32_to_cpu(*buf); 457f1ae32a1SGerd Hoffmann } 458f1ae32a1SGerd Hoffmann 459cf66ee8eSAlexey Kardashevskiy return 0; 460f1ae32a1SGerd Hoffmann } 461f1ae32a1SGerd Hoffmann 462f1ae32a1SGerd Hoffmann /* Put an array of dwords in to main memory */ 463f1ae32a1SGerd Hoffmann static inline int put_dwords(OHCIState *ohci, 4649ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 465f1ae32a1SGerd Hoffmann { 466f1ae32a1SGerd Hoffmann int i; 467f1ae32a1SGerd Hoffmann 468f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 469f1ae32a1SGerd Hoffmann 470f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 471f1ae32a1SGerd Hoffmann uint32_t tmp = cpu_to_le32(*buf); 472cf66ee8eSAlexey Kardashevskiy if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { 473cf66ee8eSAlexey Kardashevskiy return -1; 474cf66ee8eSAlexey Kardashevskiy } 475f1ae32a1SGerd Hoffmann } 476f1ae32a1SGerd Hoffmann 477cf66ee8eSAlexey Kardashevskiy return 0; 478f1ae32a1SGerd Hoffmann } 479f1ae32a1SGerd Hoffmann 480f1ae32a1SGerd Hoffmann /* Get an array of words from main memory */ 481f1ae32a1SGerd Hoffmann static inline int get_words(OHCIState *ohci, 4829ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 483f1ae32a1SGerd Hoffmann { 484f1ae32a1SGerd Hoffmann int i; 485f1ae32a1SGerd Hoffmann 486f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 487f1ae32a1SGerd Hoffmann 488f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 489cf66ee8eSAlexey Kardashevskiy if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { 490cf66ee8eSAlexey Kardashevskiy return -1; 491cf66ee8eSAlexey Kardashevskiy } 492f1ae32a1SGerd Hoffmann *buf = le16_to_cpu(*buf); 493f1ae32a1SGerd Hoffmann } 494f1ae32a1SGerd Hoffmann 495cf66ee8eSAlexey Kardashevskiy return 0; 496f1ae32a1SGerd Hoffmann } 497f1ae32a1SGerd Hoffmann 498f1ae32a1SGerd Hoffmann /* Put an array of words in to main memory */ 499f1ae32a1SGerd Hoffmann static inline int put_words(OHCIState *ohci, 5009ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 501f1ae32a1SGerd Hoffmann { 502f1ae32a1SGerd Hoffmann int i; 503f1ae32a1SGerd Hoffmann 504f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 505f1ae32a1SGerd Hoffmann 506f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 507f1ae32a1SGerd Hoffmann uint16_t tmp = cpu_to_le16(*buf); 508cf66ee8eSAlexey Kardashevskiy if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { 509cf66ee8eSAlexey Kardashevskiy return -1; 510cf66ee8eSAlexey Kardashevskiy } 511f1ae32a1SGerd Hoffmann } 512f1ae32a1SGerd Hoffmann 513cf66ee8eSAlexey Kardashevskiy return 0; 514f1ae32a1SGerd Hoffmann } 515f1ae32a1SGerd Hoffmann 516f1ae32a1SGerd Hoffmann static inline int ohci_read_ed(OHCIState *ohci, 5179ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 518f1ae32a1SGerd Hoffmann { 519f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2); 520f1ae32a1SGerd Hoffmann } 521f1ae32a1SGerd Hoffmann 522f1ae32a1SGerd Hoffmann static inline int ohci_read_td(OHCIState *ohci, 5239ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 524f1ae32a1SGerd Hoffmann { 525f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 526f1ae32a1SGerd Hoffmann } 527f1ae32a1SGerd Hoffmann 528f1ae32a1SGerd Hoffmann static inline int ohci_read_iso_td(OHCIState *ohci, 5299ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 530f1ae32a1SGerd Hoffmann { 531cf66ee8eSAlexey Kardashevskiy return get_dwords(ohci, addr, (uint32_t *)td, 4) || 532cf66ee8eSAlexey Kardashevskiy get_words(ohci, addr + 16, td->offset, 8); 533f1ae32a1SGerd Hoffmann } 534f1ae32a1SGerd Hoffmann 535f1ae32a1SGerd Hoffmann static inline int ohci_read_hcca(OHCIState *ohci, 5369ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 537f1ae32a1SGerd Hoffmann { 538cf66ee8eSAlexey Kardashevskiy return dma_memory_read(ohci->as, addr + ohci->localmem_base, 539cf66ee8eSAlexey Kardashevskiy hcca, sizeof(*hcca)); 540f1ae32a1SGerd Hoffmann } 541f1ae32a1SGerd Hoffmann 542f1ae32a1SGerd Hoffmann static inline int ohci_put_ed(OHCIState *ohci, 5439ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 544f1ae32a1SGerd Hoffmann { 54586e18caeSWei Yang /* ed->tail is under control of the HCD. 54686e18caeSWei Yang * Since just ed->head is changed by HC, just write back this 54786e18caeSWei Yang */ 54886e18caeSWei Yang 54986e18caeSWei Yang return put_dwords(ohci, addr + ED_WBACK_OFFSET, 55086e18caeSWei Yang (uint32_t *)((char *)ed + ED_WBACK_OFFSET), 55186e18caeSWei Yang ED_WBACK_SIZE >> 2); 552f1ae32a1SGerd Hoffmann } 553f1ae32a1SGerd Hoffmann 554f1ae32a1SGerd Hoffmann static inline int ohci_put_td(OHCIState *ohci, 5559ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 556f1ae32a1SGerd Hoffmann { 557f1ae32a1SGerd Hoffmann return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 558f1ae32a1SGerd Hoffmann } 559f1ae32a1SGerd Hoffmann 560f1ae32a1SGerd Hoffmann static inline int ohci_put_iso_td(OHCIState *ohci, 5619ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 562f1ae32a1SGerd Hoffmann { 563cae7f29cSJack Un return put_dwords(ohci, addr, (uint32_t *)td, 4) || 564cae7f29cSJack Un put_words(ohci, addr + 16, td->offset, 8); 565f1ae32a1SGerd Hoffmann } 566f1ae32a1SGerd Hoffmann 567f1ae32a1SGerd Hoffmann static inline int ohci_put_hcca(OHCIState *ohci, 5689ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 569f1ae32a1SGerd Hoffmann { 570cf66ee8eSAlexey Kardashevskiy return dma_memory_write(ohci->as, 5719ac6a217SDavid Gibson addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, 57286e18caeSWei Yang (char *)hcca + HCCA_WRITEBACK_OFFSET, 57386e18caeSWei Yang HCCA_WRITEBACK_SIZE); 574f1ae32a1SGerd Hoffmann } 575f1ae32a1SGerd Hoffmann 576f1ae32a1SGerd Hoffmann /* Read/Write the contents of a TD from/to main memory. */ 577cf66ee8eSAlexey Kardashevskiy static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, 5789ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 579f1ae32a1SGerd Hoffmann { 5809ac6a217SDavid Gibson dma_addr_t ptr, n; 581f1ae32a1SGerd Hoffmann 582f1ae32a1SGerd Hoffmann ptr = td->cbp; 583f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 584f1ae32a1SGerd Hoffmann if (n > len) 585f1ae32a1SGerd Hoffmann n = len; 586cf66ee8eSAlexey Kardashevskiy 587cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { 588cf66ee8eSAlexey Kardashevskiy return -1; 589cf66ee8eSAlexey Kardashevskiy } 590cf66ee8eSAlexey Kardashevskiy if (n == len) { 591cf66ee8eSAlexey Kardashevskiy return 0; 592cf66ee8eSAlexey Kardashevskiy } 593f1ae32a1SGerd Hoffmann ptr = td->be & ~0xfffu; 594f1ae32a1SGerd Hoffmann buf += n; 595cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 596cf66ee8eSAlexey Kardashevskiy len - n, dir)) { 597cf66ee8eSAlexey Kardashevskiy return -1; 598cf66ee8eSAlexey Kardashevskiy } 599cf66ee8eSAlexey Kardashevskiy return 0; 600f1ae32a1SGerd Hoffmann } 601f1ae32a1SGerd Hoffmann 602f1ae32a1SGerd Hoffmann /* Read/Write the contents of an ISO TD from/to main memory. */ 603cf66ee8eSAlexey Kardashevskiy static int ohci_copy_iso_td(OHCIState *ohci, 604f1ae32a1SGerd Hoffmann uint32_t start_addr, uint32_t end_addr, 6059ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 606f1ae32a1SGerd Hoffmann { 6079ac6a217SDavid Gibson dma_addr_t ptr, n; 608f1ae32a1SGerd Hoffmann 609f1ae32a1SGerd Hoffmann ptr = start_addr; 610f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 611f1ae32a1SGerd Hoffmann if (n > len) 612f1ae32a1SGerd Hoffmann n = len; 613cf66ee8eSAlexey Kardashevskiy 614cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { 615cf66ee8eSAlexey Kardashevskiy return -1; 616cf66ee8eSAlexey Kardashevskiy } 617cf66ee8eSAlexey Kardashevskiy if (n == len) { 618cf66ee8eSAlexey Kardashevskiy return 0; 619cf66ee8eSAlexey Kardashevskiy } 620f1ae32a1SGerd Hoffmann ptr = end_addr & ~0xfffu; 621f1ae32a1SGerd Hoffmann buf += n; 622cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 623cf66ee8eSAlexey Kardashevskiy len - n, dir)) { 624cf66ee8eSAlexey Kardashevskiy return -1; 625cf66ee8eSAlexey Kardashevskiy } 626cf66ee8eSAlexey Kardashevskiy return 0; 627f1ae32a1SGerd Hoffmann } 628f1ae32a1SGerd Hoffmann 629f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion); 630f1ae32a1SGerd Hoffmann 631f1ae32a1SGerd Hoffmann static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) 632f1ae32a1SGerd Hoffmann { 633f1ae32a1SGerd Hoffmann OHCIState *ohci = container_of(packet, OHCIState, usb_packet); 634dc1f5988SAlexey Kardashevskiy 635dc1f5988SAlexey Kardashevskiy trace_usb_ohci_async_complete(); 63669e25d26SAlexey Kardashevskiy ohci->async_complete = true; 637f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 1); 638f1ae32a1SGerd Hoffmann } 639f1ae32a1SGerd Hoffmann 640f1ae32a1SGerd Hoffmann #define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b))) 641f1ae32a1SGerd Hoffmann 642f1ae32a1SGerd Hoffmann static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, 643f1ae32a1SGerd Hoffmann int completion) 644f1ae32a1SGerd Hoffmann { 645f1ae32a1SGerd Hoffmann int dir; 646f1ae32a1SGerd Hoffmann size_t len = 0; 647f1ae32a1SGerd Hoffmann const char *str = NULL; 648f1ae32a1SGerd Hoffmann int pid; 649f1ae32a1SGerd Hoffmann int ret; 650f1ae32a1SGerd Hoffmann int i; 651f1ae32a1SGerd Hoffmann USBDevice *dev; 652f1ae32a1SGerd Hoffmann USBEndpoint *ep; 653f1ae32a1SGerd Hoffmann struct ohci_iso_td iso_td; 654f1ae32a1SGerd Hoffmann uint32_t addr; 655f1ae32a1SGerd Hoffmann uint16_t starting_frame; 656f1ae32a1SGerd Hoffmann int16_t relative_frame_number; 657f1ae32a1SGerd Hoffmann int frame_count; 658f1ae32a1SGerd Hoffmann uint32_t start_offset, next_offset, end_offset = 0; 659f1ae32a1SGerd Hoffmann uint32_t start_addr, end_addr; 660f1ae32a1SGerd Hoffmann 661f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 662f1ae32a1SGerd Hoffmann 663cf66ee8eSAlexey Kardashevskiy if (ohci_read_iso_td(ohci, addr, &iso_td)) { 664dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_read_failed(addr); 665cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 66626f670a2SLi Qiang return 1; 667f1ae32a1SGerd Hoffmann } 668f1ae32a1SGerd Hoffmann 669f1ae32a1SGerd Hoffmann starting_frame = OHCI_BM(iso_td.flags, TD_SF); 670f1ae32a1SGerd Hoffmann frame_count = OHCI_BM(iso_td.flags, TD_FC); 671f1ae32a1SGerd Hoffmann relative_frame_number = USUB(ohci->frame_number, starting_frame); 672f1ae32a1SGerd Hoffmann 673dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_head( 674f1ae32a1SGerd Hoffmann ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK, 675f1ae32a1SGerd Hoffmann iso_td.flags, iso_td.bp, iso_td.next, iso_td.be, 676f1ae32a1SGerd Hoffmann ohci->frame_number, starting_frame, 677bc0d104cSAlex Bennée frame_count, relative_frame_number); 6783af8f177SAlexey Kardashevskiy trace_usb_ohci_iso_td_head_offset( 6793af8f177SAlexey Kardashevskiy iso_td.offset[0], iso_td.offset[1], 6803af8f177SAlexey Kardashevskiy iso_td.offset[2], iso_td.offset[3], 6813af8f177SAlexey Kardashevskiy iso_td.offset[4], iso_td.offset[5], 6823af8f177SAlexey Kardashevskiy iso_td.offset[6], iso_td.offset[7]); 683f1ae32a1SGerd Hoffmann 684f1ae32a1SGerd Hoffmann if (relative_frame_number < 0) { 685dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number); 686f1ae32a1SGerd Hoffmann return 1; 687f1ae32a1SGerd Hoffmann } else if (relative_frame_number > frame_count) { 688f1ae32a1SGerd Hoffmann /* ISO TD expired - retire the TD to the Done Queue and continue with 689f1ae32a1SGerd Hoffmann the next ISO TD of the same ED */ 690dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number, 691f1ae32a1SGerd Hoffmann frame_count); 692f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 693f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 694f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 695f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 696f1ae32a1SGerd Hoffmann ohci->done = addr; 697f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 698f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 699f1ae32a1SGerd Hoffmann ohci->done_count = i; 700cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 701cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 702cf66ee8eSAlexey Kardashevskiy return 1; 703cf66ee8eSAlexey Kardashevskiy } 704f1ae32a1SGerd Hoffmann return 0; 705f1ae32a1SGerd Hoffmann } 706f1ae32a1SGerd Hoffmann 707f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 708f1ae32a1SGerd Hoffmann switch (dir) { 709f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 710f1ae32a1SGerd Hoffmann str = "in"; 711f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 712f1ae32a1SGerd Hoffmann break; 713f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 714f1ae32a1SGerd Hoffmann str = "out"; 715f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 716f1ae32a1SGerd Hoffmann break; 717f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 718f1ae32a1SGerd Hoffmann str = "setup"; 719f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 720f1ae32a1SGerd Hoffmann break; 721f1ae32a1SGerd Hoffmann default: 722dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_direction(dir); 723f1ae32a1SGerd Hoffmann return 1; 724f1ae32a1SGerd Hoffmann } 725f1ae32a1SGerd Hoffmann 726f1ae32a1SGerd Hoffmann if (!iso_td.bp || !iso_td.be) { 727dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be); 728f1ae32a1SGerd Hoffmann return 1; 729f1ae32a1SGerd Hoffmann } 730f1ae32a1SGerd Hoffmann 731f1ae32a1SGerd Hoffmann start_offset = iso_td.offset[relative_frame_number]; 732f1ae32a1SGerd Hoffmann next_offset = iso_td.offset[relative_frame_number + 1]; 733f1ae32a1SGerd Hoffmann 734f1ae32a1SGerd Hoffmann if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 735f1ae32a1SGerd Hoffmann ((relative_frame_number < frame_count) && 736f1ae32a1SGerd Hoffmann !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) { 737dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset); 738f1ae32a1SGerd Hoffmann return 1; 739f1ae32a1SGerd Hoffmann } 740f1ae32a1SGerd Hoffmann 741f1ae32a1SGerd Hoffmann if ((relative_frame_number < frame_count) && (start_offset > next_offset)) { 742dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset); 743f1ae32a1SGerd Hoffmann return 1; 744f1ae32a1SGerd Hoffmann } 745f1ae32a1SGerd Hoffmann 746f1ae32a1SGerd Hoffmann if ((start_offset & 0x1000) == 0) { 747f1ae32a1SGerd Hoffmann start_addr = (iso_td.bp & OHCI_PAGE_MASK) | 748f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 749f1ae32a1SGerd Hoffmann } else { 750f1ae32a1SGerd Hoffmann start_addr = (iso_td.be & OHCI_PAGE_MASK) | 751f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 752f1ae32a1SGerd Hoffmann } 753f1ae32a1SGerd Hoffmann 754f1ae32a1SGerd Hoffmann if (relative_frame_number < frame_count) { 755f1ae32a1SGerd Hoffmann end_offset = next_offset - 1; 756f1ae32a1SGerd Hoffmann if ((end_offset & 0x1000) == 0) { 757f1ae32a1SGerd Hoffmann end_addr = (iso_td.bp & OHCI_PAGE_MASK) | 758f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 759f1ae32a1SGerd Hoffmann } else { 760f1ae32a1SGerd Hoffmann end_addr = (iso_td.be & OHCI_PAGE_MASK) | 761f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 762f1ae32a1SGerd Hoffmann } 763f1ae32a1SGerd Hoffmann } else { 764f1ae32a1SGerd Hoffmann /* Last packet in the ISO TD */ 765f1ae32a1SGerd Hoffmann end_addr = iso_td.be; 766f1ae32a1SGerd Hoffmann } 767f1ae32a1SGerd Hoffmann 768f1ae32a1SGerd Hoffmann if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { 769f1ae32a1SGerd Hoffmann len = (end_addr & OHCI_OFFSET_MASK) + 0x1001 770f1ae32a1SGerd Hoffmann - (start_addr & OHCI_OFFSET_MASK); 771f1ae32a1SGerd Hoffmann } else { 772f1ae32a1SGerd Hoffmann len = end_addr - start_addr + 1; 773f1ae32a1SGerd Hoffmann } 774f1ae32a1SGerd Hoffmann 775f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 776cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 777cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 778cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 779cf66ee8eSAlexey Kardashevskiy return 1; 780cf66ee8eSAlexey Kardashevskiy } 781f1ae32a1SGerd Hoffmann } 782f1ae32a1SGerd Hoffmann 7839a77a0f5SHans de Goede if (!completion) { 784a6fb2ddbSHans de Goede bool int_req = relative_frame_number == frame_count && 785a6fb2ddbSHans de Goede OHCI_BM(iso_td.flags, TD_DI) == 0; 786f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 78742340fc3SLiam Merwick if (dev == NULL) { 78842340fc3SLiam Merwick trace_usb_ohci_td_dev_error(); 78942340fc3SLiam Merwick return 1; 79042340fc3SLiam Merwick } 791f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 7928550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req); 793f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); 7949a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 7959a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 79636dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 797f1ae32a1SGerd Hoffmann return 1; 798f1ae32a1SGerd Hoffmann } 799f1ae32a1SGerd Hoffmann } 8009a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 8019a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 8029a77a0f5SHans de Goede } else { 8039a77a0f5SHans de Goede ret = ohci->usb_packet.status; 8049a77a0f5SHans de Goede } 805f1ae32a1SGerd Hoffmann 806dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr, 807dc1f5988SAlexey Kardashevskiy str, len, ret); 808f1ae32a1SGerd Hoffmann 809f1ae32a1SGerd Hoffmann /* Writeback */ 810f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) { 811f1ae32a1SGerd Hoffmann /* IN transfer succeeded */ 812cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 813cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 814cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 815cf66ee8eSAlexey Kardashevskiy return 1; 816cf66ee8eSAlexey Kardashevskiy } 817f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 818f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 819f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret); 820f1ae32a1SGerd Hoffmann } else if (dir == OHCI_TD_DIR_OUT && ret == len) { 821f1ae32a1SGerd Hoffmann /* OUT transfer succeeded */ 822f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 823f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 824f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); 825f1ae32a1SGerd Hoffmann } else { 826f1ae32a1SGerd Hoffmann if (ret > (ssize_t) len) { 827dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_overrun(ret, len); 828f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 829f1ae32a1SGerd Hoffmann OHCI_CC_DATAOVERRUN); 830f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 831f1ae32a1SGerd Hoffmann len); 832f1ae32a1SGerd Hoffmann } else if (ret >= 0) { 833dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_underrun(ret); 834f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 835f1ae32a1SGerd Hoffmann OHCI_CC_DATAUNDERRUN); 836f1ae32a1SGerd Hoffmann } else { 837f1ae32a1SGerd Hoffmann switch (ret) { 838f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 839f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 840f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 841f1ae32a1SGerd Hoffmann OHCI_CC_DEVICENOTRESPONDING); 842f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 843f1ae32a1SGerd Hoffmann 0); 844f1ae32a1SGerd Hoffmann break; 845f1ae32a1SGerd Hoffmann case USB_RET_NAK: 846f1ae32a1SGerd Hoffmann case USB_RET_STALL: 847dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_nak(ret); 848f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 849f1ae32a1SGerd Hoffmann OHCI_CC_STALL); 850f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 851f1ae32a1SGerd Hoffmann 0); 852f1ae32a1SGerd Hoffmann break; 853f1ae32a1SGerd Hoffmann default: 854dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_response(ret); 855f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 856f1ae32a1SGerd Hoffmann OHCI_CC_UNDEXPETEDPID); 857f1ae32a1SGerd Hoffmann break; 858f1ae32a1SGerd Hoffmann } 859f1ae32a1SGerd Hoffmann } 860f1ae32a1SGerd Hoffmann } 861f1ae32a1SGerd Hoffmann 862f1ae32a1SGerd Hoffmann if (relative_frame_number == frame_count) { 863f1ae32a1SGerd Hoffmann /* Last data packet of ISO TD - retire the TD to the Done Queue */ 864f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR); 865f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 866f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 867f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 868f1ae32a1SGerd Hoffmann ohci->done = addr; 869f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 870f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 871f1ae32a1SGerd Hoffmann ohci->done_count = i; 872f1ae32a1SGerd Hoffmann } 873cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 874cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 875cf66ee8eSAlexey Kardashevskiy } 876f1ae32a1SGerd Hoffmann return 1; 877f1ae32a1SGerd Hoffmann } 878f1ae32a1SGerd Hoffmann 879dc1f5988SAlexey Kardashevskiy static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) 880dc1f5988SAlexey Kardashevskiy { 881d87aa138SStefan Hajnoczi bool print16; 882d87aa138SStefan Hajnoczi bool printall; 883dc1f5988SAlexey Kardashevskiy const int width = 16; 884dc1f5988SAlexey Kardashevskiy int i; 885dc1f5988SAlexey Kardashevskiy char tmp[3 * width + 1]; 886dc1f5988SAlexey Kardashevskiy char *p = tmp; 887dc1f5988SAlexey Kardashevskiy 888d87aa138SStefan Hajnoczi print16 = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_SHORT); 889d87aa138SStefan Hajnoczi printall = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_FULL); 890d87aa138SStefan Hajnoczi 891dc1f5988SAlexey Kardashevskiy if (!printall && !print16) { 892dc1f5988SAlexey Kardashevskiy return; 893dc1f5988SAlexey Kardashevskiy } 894dc1f5988SAlexey Kardashevskiy 895dc1f5988SAlexey Kardashevskiy for (i = 0; ; i++) { 896dc1f5988SAlexey Kardashevskiy if (i && (!(i % width) || (i == len))) { 897dc1f5988SAlexey Kardashevskiy if (!printall) { 898dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_short(msg, tmp); 899dc1f5988SAlexey Kardashevskiy break; 900dc1f5988SAlexey Kardashevskiy } 901dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_full(msg, tmp); 902dc1f5988SAlexey Kardashevskiy p = tmp; 903dc1f5988SAlexey Kardashevskiy *p = 0; 904dc1f5988SAlexey Kardashevskiy } 905dc1f5988SAlexey Kardashevskiy if (i == len) { 906dc1f5988SAlexey Kardashevskiy break; 907dc1f5988SAlexey Kardashevskiy } 908dc1f5988SAlexey Kardashevskiy 909dc1f5988SAlexey Kardashevskiy p += sprintf(p, " %.2x", buf[i]); 910dc1f5988SAlexey Kardashevskiy } 911dc1f5988SAlexey Kardashevskiy } 912dc1f5988SAlexey Kardashevskiy 913f1ae32a1SGerd Hoffmann /* Service a transport descriptor. 914f1ae32a1SGerd Hoffmann Returns nonzero to terminate processing of this endpoint. */ 915f1ae32a1SGerd Hoffmann 916f1ae32a1SGerd Hoffmann static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) 917f1ae32a1SGerd Hoffmann { 918f1ae32a1SGerd Hoffmann int dir; 919f1ae32a1SGerd Hoffmann size_t len = 0, pktlen = 0; 920f1ae32a1SGerd Hoffmann const char *str = NULL; 921f1ae32a1SGerd Hoffmann int pid; 922f1ae32a1SGerd Hoffmann int ret; 923f1ae32a1SGerd Hoffmann int i; 924f1ae32a1SGerd Hoffmann USBDevice *dev; 925f1ae32a1SGerd Hoffmann USBEndpoint *ep; 926f1ae32a1SGerd Hoffmann struct ohci_td td; 927f1ae32a1SGerd Hoffmann uint32_t addr; 928f1ae32a1SGerd Hoffmann int flag_r; 929f1ae32a1SGerd Hoffmann int completion; 930f1ae32a1SGerd Hoffmann 931f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 932f1ae32a1SGerd Hoffmann /* See if this TD has already been submitted to the device. */ 933f1ae32a1SGerd Hoffmann completion = (addr == ohci->async_td); 934f1ae32a1SGerd Hoffmann if (completion && !ohci->async_complete) { 935dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_skip_async(); 936f1ae32a1SGerd Hoffmann return 1; 937f1ae32a1SGerd Hoffmann } 938cf66ee8eSAlexey Kardashevskiy if (ohci_read_td(ohci, addr, &td)) { 939dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_read_error(addr); 940cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 9416ebc069dSLi Qiang return 1; 942f1ae32a1SGerd Hoffmann } 943f1ae32a1SGerd Hoffmann 944f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 945f1ae32a1SGerd Hoffmann switch (dir) { 946f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 947f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 948f1ae32a1SGerd Hoffmann /* Same value. */ 949f1ae32a1SGerd Hoffmann break; 950f1ae32a1SGerd Hoffmann default: 951f1ae32a1SGerd Hoffmann dir = OHCI_BM(td.flags, TD_DP); 952f1ae32a1SGerd Hoffmann break; 953f1ae32a1SGerd Hoffmann } 954f1ae32a1SGerd Hoffmann 955f1ae32a1SGerd Hoffmann switch (dir) { 956f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 957f1ae32a1SGerd Hoffmann str = "in"; 958f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 959f1ae32a1SGerd Hoffmann break; 960f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 961f1ae32a1SGerd Hoffmann str = "out"; 962f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 963f1ae32a1SGerd Hoffmann break; 964f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 965f1ae32a1SGerd Hoffmann str = "setup"; 966f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 967f1ae32a1SGerd Hoffmann break; 968f1ae32a1SGerd Hoffmann default: 969dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_direction(dir); 970f1ae32a1SGerd Hoffmann return 1; 971f1ae32a1SGerd Hoffmann } 972f1ae32a1SGerd Hoffmann if (td.cbp && td.be) { 973f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { 974f1ae32a1SGerd Hoffmann len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); 975f1ae32a1SGerd Hoffmann } else { 976f1ae32a1SGerd Hoffmann len = (td.be - td.cbp) + 1; 977f1ae32a1SGerd Hoffmann } 978f1ae32a1SGerd Hoffmann 979f1ae32a1SGerd Hoffmann pktlen = len; 980f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 981f1ae32a1SGerd Hoffmann /* The endpoint may not allow us to transfer it all now */ 982f1ae32a1SGerd Hoffmann pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT; 983f1ae32a1SGerd Hoffmann if (pktlen > len) { 984f1ae32a1SGerd Hoffmann pktlen = len; 985f1ae32a1SGerd Hoffmann } 986f1ae32a1SGerd Hoffmann if (!completion) { 987cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 988cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 989cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 990cf66ee8eSAlexey Kardashevskiy } 991f1ae32a1SGerd Hoffmann } 992f1ae32a1SGerd Hoffmann } 993f1ae32a1SGerd Hoffmann } 994f1ae32a1SGerd Hoffmann 995f1ae32a1SGerd Hoffmann flag_r = (td.flags & OHCI_TD_R) != 0; 996dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str, 997dc1f5988SAlexey Kardashevskiy flag_r, td.cbp, td.be); 998dc1f5988SAlexey Kardashevskiy ohci_td_pkt("OUT", ohci->usb_buf, pktlen); 999f1ae32a1SGerd Hoffmann 1000f1ae32a1SGerd Hoffmann if (completion) { 1001f1ae32a1SGerd Hoffmann ohci->async_td = 0; 100269e25d26SAlexey Kardashevskiy ohci->async_complete = false; 1003f1ae32a1SGerd Hoffmann } else { 1004f1ae32a1SGerd Hoffmann if (ohci->async_td) { 1005f1ae32a1SGerd Hoffmann /* ??? The hardware should allow one active packet per 1006f1ae32a1SGerd Hoffmann endpoint. We only allow one active packet per controller. 1007f1ae32a1SGerd Hoffmann This should be sufficient as long as devices respond in a 1008f1ae32a1SGerd Hoffmann timely manner. 1009f1ae32a1SGerd Hoffmann */ 1010dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_too_many_pending(); 1011f1ae32a1SGerd Hoffmann return 1; 1012f1ae32a1SGerd Hoffmann } 1013f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 101442340fc3SLiam Merwick if (dev == NULL) { 101542340fc3SLiam Merwick trace_usb_ohci_td_dev_error(); 101642340fc3SLiam Merwick return 1; 101742340fc3SLiam Merwick } 1018f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 10198550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r, 1020a6fb2ddbSHans de Goede OHCI_BM(td.flags, TD_DI) == 0); 1021f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); 10229a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 1023dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_packet_status(ohci->usb_packet.status); 1024dc1f5988SAlexey Kardashevskiy 10259a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 102636dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 1027f1ae32a1SGerd Hoffmann ohci->async_td = addr; 1028f1ae32a1SGerd Hoffmann return 1; 1029f1ae32a1SGerd Hoffmann } 1030f1ae32a1SGerd Hoffmann } 10319a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 10329a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 10339a77a0f5SHans de Goede } else { 10349a77a0f5SHans de Goede ret = ohci->usb_packet.status; 10359a77a0f5SHans de Goede } 10369a77a0f5SHans de Goede 1037f1ae32a1SGerd Hoffmann if (ret >= 0) { 1038f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN) { 1039cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1040cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 1041cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1042cf66ee8eSAlexey Kardashevskiy } 1043dc1f5988SAlexey Kardashevskiy ohci_td_pkt("IN", ohci->usb_buf, pktlen); 1044f1ae32a1SGerd Hoffmann } else { 1045f1ae32a1SGerd Hoffmann ret = pktlen; 1046f1ae32a1SGerd Hoffmann } 1047f1ae32a1SGerd Hoffmann } 1048f1ae32a1SGerd Hoffmann 1049f1ae32a1SGerd Hoffmann /* Writeback */ 1050f1ae32a1SGerd Hoffmann if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { 1051f1ae32a1SGerd Hoffmann /* Transmission succeeded. */ 1052f1ae32a1SGerd Hoffmann if (ret == len) { 1053f1ae32a1SGerd Hoffmann td.cbp = 0; 1054f1ae32a1SGerd Hoffmann } else { 1055f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfff) + ret > 0xfff) { 1056f1ae32a1SGerd Hoffmann td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff); 1057f1ae32a1SGerd Hoffmann } else { 1058f1ae32a1SGerd Hoffmann td.cbp += ret; 1059f1ae32a1SGerd Hoffmann } 1060f1ae32a1SGerd Hoffmann } 1061f1ae32a1SGerd Hoffmann td.flags |= OHCI_TD_T1; 1062f1ae32a1SGerd Hoffmann td.flags ^= OHCI_TD_T0; 1063f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); 1064f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 0); 1065f1ae32a1SGerd Hoffmann 1066f1ae32a1SGerd Hoffmann if ((dir != OHCI_TD_DIR_IN) && (ret != len)) { 1067f1ae32a1SGerd Hoffmann /* Partial packet transfer: TD not ready to retire yet */ 1068f1ae32a1SGerd Hoffmann goto exit_no_retire; 1069f1ae32a1SGerd Hoffmann } 1070f1ae32a1SGerd Hoffmann 1071f1ae32a1SGerd Hoffmann /* Setting ED_C is part of the TD retirement process */ 1072f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_ED_C; 1073f1ae32a1SGerd Hoffmann if (td.flags & OHCI_TD_T0) 1074f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_C; 1075f1ae32a1SGerd Hoffmann } else { 1076f1ae32a1SGerd Hoffmann if (ret >= 0) { 1077dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_underrun(); 1078f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); 1079f1ae32a1SGerd Hoffmann } else { 1080f1ae32a1SGerd Hoffmann switch (ret) { 1081f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 1082f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 1083dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_dev_error(); 1084f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); 10854b351a0fSJán Veselý break; 1086f1ae32a1SGerd Hoffmann case USB_RET_NAK: 1087dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_nak(); 1088f1ae32a1SGerd Hoffmann return 1; 1089f1ae32a1SGerd Hoffmann case USB_RET_STALL: 1090dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_stall(); 1091f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); 1092f1ae32a1SGerd Hoffmann break; 1093f1ae32a1SGerd Hoffmann case USB_RET_BABBLE: 1094dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_babble(); 1095f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 1096f1ae32a1SGerd Hoffmann break; 1097f1ae32a1SGerd Hoffmann default: 1098dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_device_response(ret); 1099f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); 1100f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 3); 1101f1ae32a1SGerd Hoffmann break; 1102f1ae32a1SGerd Hoffmann } 11037c48b95dSSebastian Bauer /* An error occured so we have to clear the interrupt counter. See 11047c48b95dSSebastian Bauer * spec at 6.4.4 on page 104 */ 11057c48b95dSSebastian Bauer ohci->done_count = 0; 1106f1ae32a1SGerd Hoffmann } 1107f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_H; 1108f1ae32a1SGerd Hoffmann } 1109f1ae32a1SGerd Hoffmann 1110f1ae32a1SGerd Hoffmann /* Retire this TD */ 1111f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 1112f1ae32a1SGerd Hoffmann ed->head |= td.next & OHCI_DPTR_MASK; 1113f1ae32a1SGerd Hoffmann td.next = ohci->done; 1114f1ae32a1SGerd Hoffmann ohci->done = addr; 1115f1ae32a1SGerd Hoffmann i = OHCI_BM(td.flags, TD_DI); 1116f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 1117f1ae32a1SGerd Hoffmann ohci->done_count = i; 1118f1ae32a1SGerd Hoffmann exit_no_retire: 1119cf66ee8eSAlexey Kardashevskiy if (ohci_put_td(ohci, addr, &td)) { 1120cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1121cf66ee8eSAlexey Kardashevskiy return 1; 1122cf66ee8eSAlexey Kardashevskiy } 1123f1ae32a1SGerd Hoffmann return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; 1124f1ae32a1SGerd Hoffmann } 1125f1ae32a1SGerd Hoffmann 1126f1ae32a1SGerd Hoffmann /* Service an endpoint list. Returns nonzero if active TD were found. */ 1127f1ae32a1SGerd Hoffmann static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) 1128f1ae32a1SGerd Hoffmann { 1129f1ae32a1SGerd Hoffmann struct ohci_ed ed; 1130f1ae32a1SGerd Hoffmann uint32_t next_ed; 1131f1ae32a1SGerd Hoffmann uint32_t cur; 1132f1ae32a1SGerd Hoffmann int active; 113395ed5693SLi Qiang uint32_t link_cnt = 0; 1134f1ae32a1SGerd Hoffmann active = 0; 1135f1ae32a1SGerd Hoffmann 1136f1ae32a1SGerd Hoffmann if (head == 0) 1137f1ae32a1SGerd Hoffmann return 0; 1138f1ae32a1SGerd Hoffmann 1139ab878998SLaurent Vivier for (cur = head; cur && link_cnt++ < ED_LINK_LIMIT; cur = next_ed) { 1140cf66ee8eSAlexey Kardashevskiy if (ohci_read_ed(ohci, cur, &ed)) { 1141dc1f5988SAlexey Kardashevskiy trace_usb_ohci_ed_read_error(cur); 1142cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1143f1ae32a1SGerd Hoffmann return 0; 1144f1ae32a1SGerd Hoffmann } 1145f1ae32a1SGerd Hoffmann 1146f1ae32a1SGerd Hoffmann next_ed = ed.next & OHCI_DPTR_MASK; 1147f1ae32a1SGerd Hoffmann 1148f1ae32a1SGerd Hoffmann if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) { 1149f1ae32a1SGerd Hoffmann uint32_t addr; 1150f1ae32a1SGerd Hoffmann /* Cancel pending packets for ED that have been paused. */ 1151f1ae32a1SGerd Hoffmann addr = ed.head & OHCI_DPTR_MASK; 1152f1ae32a1SGerd Hoffmann if (ohci->async_td && addr == ohci->async_td) { 1153f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1154f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1155f79738b0SHans de Goede usb_device_ep_stopped(ohci->usb_packet.ep->dev, 1156f79738b0SHans de Goede ohci->usb_packet.ep); 1157f1ae32a1SGerd Hoffmann } 1158f1ae32a1SGerd Hoffmann continue; 1159f1ae32a1SGerd Hoffmann } 1160f1ae32a1SGerd Hoffmann 1161f1ae32a1SGerd Hoffmann while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { 11623af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0, 11633af8f177SAlexey Kardashevskiy (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, 11643af8f177SAlexey Kardashevskiy ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); 11653af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt_flags( 1166f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), 1167f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, 1168f1ae32a1SGerd Hoffmann (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, 11693af8f177SAlexey Kardashevskiy OHCI_BM(ed.flags, ED_MPS)); 1170dc1f5988SAlexey Kardashevskiy 1171f1ae32a1SGerd Hoffmann active = 1; 1172f1ae32a1SGerd Hoffmann 1173f1ae32a1SGerd Hoffmann if ((ed.flags & OHCI_ED_F) == 0) { 1174f1ae32a1SGerd Hoffmann if (ohci_service_td(ohci, &ed)) 1175f1ae32a1SGerd Hoffmann break; 1176f1ae32a1SGerd Hoffmann } else { 1177f1ae32a1SGerd Hoffmann /* Handle isochronous endpoints */ 1178f1ae32a1SGerd Hoffmann if (ohci_service_iso_td(ohci, &ed, completion)) 1179f1ae32a1SGerd Hoffmann break; 1180f1ae32a1SGerd Hoffmann } 1181f1ae32a1SGerd Hoffmann } 1182f1ae32a1SGerd Hoffmann 1183cf66ee8eSAlexey Kardashevskiy if (ohci_put_ed(ohci, cur, &ed)) { 1184cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1185cf66ee8eSAlexey Kardashevskiy return 0; 1186cf66ee8eSAlexey Kardashevskiy } 1187f1ae32a1SGerd Hoffmann } 1188f1ae32a1SGerd Hoffmann 1189f1ae32a1SGerd Hoffmann return active; 1190f1ae32a1SGerd Hoffmann } 1191f1ae32a1SGerd Hoffmann 1192fd0a10cdSLaurent Vivier /* set a timer for EOF */ 1193fd0a10cdSLaurent Vivier static void ohci_eof_timer(OHCIState *ohci) 1194f1ae32a1SGerd Hoffmann { 1195bc72ad67SAlex Bligh timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time); 1196fd0a10cdSLaurent Vivier } 1197fd0a10cdSLaurent Vivier /* Set a timer for EOF and generate a SOF event */ 1198fd0a10cdSLaurent Vivier static void ohci_sof(OHCIState *ohci) 1199fd0a10cdSLaurent Vivier { 1200a60f39a4SMiguel GAIO ohci->sof_time += usb_frame_time; 1201fd0a10cdSLaurent Vivier ohci_eof_timer(ohci); 1202f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_SF); 1203f1ae32a1SGerd Hoffmann } 1204f1ae32a1SGerd Hoffmann 1205f1ae32a1SGerd Hoffmann /* Process Control and Bulk lists. */ 1206f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion) 1207f1ae32a1SGerd Hoffmann { 1208f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { 1209f1ae32a1SGerd Hoffmann if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) { 1210dc1f5988SAlexey Kardashevskiy trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur); 1211f1ae32a1SGerd Hoffmann } 1212f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) { 1213f1ae32a1SGerd Hoffmann ohci->ctrl_cur = 0; 1214f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_CLF; 1215f1ae32a1SGerd Hoffmann } 1216f1ae32a1SGerd Hoffmann } 1217f1ae32a1SGerd Hoffmann 1218f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { 1219f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) { 1220f1ae32a1SGerd Hoffmann ohci->bulk_cur = 0; 1221f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_BLF; 1222f1ae32a1SGerd Hoffmann } 1223f1ae32a1SGerd Hoffmann } 1224f1ae32a1SGerd Hoffmann } 1225f1ae32a1SGerd Hoffmann 1226f1ae32a1SGerd Hoffmann /* Do frame processing on frame boundary */ 1227f1ae32a1SGerd Hoffmann static void ohci_frame_boundary(void *opaque) 1228f1ae32a1SGerd Hoffmann { 1229f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1230f1ae32a1SGerd Hoffmann struct ohci_hcca hcca; 1231f1ae32a1SGerd Hoffmann 1232cf66ee8eSAlexey Kardashevskiy if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) { 1233dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hcca_read_error(ohci->hcca); 1234cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1235cf66ee8eSAlexey Kardashevskiy return; 1236cf66ee8eSAlexey Kardashevskiy } 1237f1ae32a1SGerd Hoffmann 1238f1ae32a1SGerd Hoffmann /* Process all the lists at the end of the frame */ 1239f1ae32a1SGerd Hoffmann if (ohci->ctl & OHCI_CTL_PLE) { 1240f1ae32a1SGerd Hoffmann int n; 1241f1ae32a1SGerd Hoffmann 1242f1ae32a1SGerd Hoffmann n = ohci->frame_number & 0x1f; 1243f1ae32a1SGerd Hoffmann ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0); 1244f1ae32a1SGerd Hoffmann } 1245f1ae32a1SGerd Hoffmann 1246f1ae32a1SGerd Hoffmann /* Cancel all pending packets if either of the lists has been disabled. */ 1247f79738b0SHans de Goede if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { 1248f79738b0SHans de Goede if (ohci->async_td) { 1249f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1250f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1251f1ae32a1SGerd Hoffmann } 1252f79738b0SHans de Goede ohci_stop_endpoints(ohci); 1253f79738b0SHans de Goede } 1254f1ae32a1SGerd Hoffmann ohci->old_ctl = ohci->ctl; 1255f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 0); 1256f1ae32a1SGerd Hoffmann 1257cf66ee8eSAlexey Kardashevskiy /* Stop if UnrecoverableError happened or ohci_sof will crash */ 1258cf66ee8eSAlexey Kardashevskiy if (ohci->intr_status & OHCI_INTR_UE) { 1259cf66ee8eSAlexey Kardashevskiy return; 1260cf66ee8eSAlexey Kardashevskiy } 1261cf66ee8eSAlexey Kardashevskiy 1262f1ae32a1SGerd Hoffmann /* Frame boundary, so do EOF stuf here */ 1263f1ae32a1SGerd Hoffmann ohci->frt = ohci->fit; 1264f1ae32a1SGerd Hoffmann 1265f1ae32a1SGerd Hoffmann /* Increment frame number and take care of endianness. */ 1266f1ae32a1SGerd Hoffmann ohci->frame_number = (ohci->frame_number + 1) & 0xffff; 1267f1ae32a1SGerd Hoffmann hcca.frame = cpu_to_le16(ohci->frame_number); 1268f1ae32a1SGerd Hoffmann 1269f1ae32a1SGerd Hoffmann if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { 1270f1ae32a1SGerd Hoffmann if (!ohci->done) 1271f1ae32a1SGerd Hoffmann abort(); 1272f1ae32a1SGerd Hoffmann if (ohci->intr & ohci->intr_status) 1273f1ae32a1SGerd Hoffmann ohci->done |= 1; 1274f1ae32a1SGerd Hoffmann hcca.done = cpu_to_le32(ohci->done); 1275f1ae32a1SGerd Hoffmann ohci->done = 0; 1276f1ae32a1SGerd Hoffmann ohci->done_count = 7; 1277f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_WD); 1278f1ae32a1SGerd Hoffmann } 1279f1ae32a1SGerd Hoffmann 1280f1ae32a1SGerd Hoffmann if (ohci->done_count != 7 && ohci->done_count != 0) 1281f1ae32a1SGerd Hoffmann ohci->done_count--; 1282f1ae32a1SGerd Hoffmann 1283f1ae32a1SGerd Hoffmann /* Do SOF stuff here */ 1284f1ae32a1SGerd Hoffmann ohci_sof(ohci); 1285f1ae32a1SGerd Hoffmann 1286f1ae32a1SGerd Hoffmann /* Writeback HCCA */ 1287cf66ee8eSAlexey Kardashevskiy if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) { 1288cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1289cf66ee8eSAlexey Kardashevskiy } 1290f1ae32a1SGerd Hoffmann } 1291f1ae32a1SGerd Hoffmann 1292f1ae32a1SGerd Hoffmann /* Start sending SOF tokens across the USB bus, lists are processed in 1293f1ae32a1SGerd Hoffmann * next frame 1294f1ae32a1SGerd Hoffmann */ 1295f1ae32a1SGerd Hoffmann static int ohci_bus_start(OHCIState *ohci) 1296f1ae32a1SGerd Hoffmann { 1297dc1f5988SAlexey Kardashevskiy trace_usb_ohci_start(ohci->name); 1298f1ae32a1SGerd Hoffmann 1299fd0a10cdSLaurent Vivier /* Delay the first SOF event by one frame time as 1300fd0a10cdSLaurent Vivier * linux driver is not ready to receive it and 1301fd0a10cdSLaurent Vivier * can meet some race conditions 1302fd0a10cdSLaurent Vivier */ 1303fd0a10cdSLaurent Vivier 1304a60f39a4SMiguel GAIO ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1305fd0a10cdSLaurent Vivier ohci_eof_timer(ohci); 1306f1ae32a1SGerd Hoffmann 1307f1ae32a1SGerd Hoffmann return 1; 1308f1ae32a1SGerd Hoffmann } 1309f1ae32a1SGerd Hoffmann 1310f1ae32a1SGerd Hoffmann /* Stop sending SOF tokens on the bus */ 131134d97308SThomas Huth void ohci_bus_stop(OHCIState *ohci) 1312f1ae32a1SGerd Hoffmann { 1313dc1f5988SAlexey Kardashevskiy trace_usb_ohci_stop(ohci->name); 1314bc72ad67SAlex Bligh timer_del(ohci->eof_timer); 1315f1ae32a1SGerd Hoffmann } 1316f1ae32a1SGerd Hoffmann 1317f1ae32a1SGerd Hoffmann /* Sets a flag in a port status register but only set it if the port is 1318f1ae32a1SGerd Hoffmann * connected, if not set ConnectStatusChange flag. If flag is enabled 1319f1ae32a1SGerd Hoffmann * return 1. 1320f1ae32a1SGerd Hoffmann */ 1321f1ae32a1SGerd Hoffmann static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) 1322f1ae32a1SGerd Hoffmann { 1323f1ae32a1SGerd Hoffmann int ret = 1; 1324f1ae32a1SGerd Hoffmann 1325f1ae32a1SGerd Hoffmann /* writing a 0 has no effect */ 1326f1ae32a1SGerd Hoffmann if (val == 0) 1327f1ae32a1SGerd Hoffmann return 0; 1328f1ae32a1SGerd Hoffmann 1329f1ae32a1SGerd Hoffmann /* If CurrentConnectStatus is cleared we set 1330f1ae32a1SGerd Hoffmann * ConnectStatusChange 1331f1ae32a1SGerd Hoffmann */ 1332f1ae32a1SGerd Hoffmann if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { 1333f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_CSC; 1334f1ae32a1SGerd Hoffmann if (ohci->rhstatus & OHCI_RHS_DRWE) { 1335f1ae32a1SGerd Hoffmann /* TODO: CSC is a wakeup event */ 1336f1ae32a1SGerd Hoffmann } 1337f1ae32a1SGerd Hoffmann return 0; 1338f1ae32a1SGerd Hoffmann } 1339f1ae32a1SGerd Hoffmann 1340f1ae32a1SGerd Hoffmann if (ohci->rhport[i].ctrl & val) 1341f1ae32a1SGerd Hoffmann ret = 0; 1342f1ae32a1SGerd Hoffmann 1343f1ae32a1SGerd Hoffmann /* set the bit */ 1344f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= val; 1345f1ae32a1SGerd Hoffmann 1346f1ae32a1SGerd Hoffmann return ret; 1347f1ae32a1SGerd Hoffmann } 1348f1ae32a1SGerd Hoffmann 1349f1ae32a1SGerd Hoffmann /* Set the frame interval - frame interval toggle is manipulated by the hcd only */ 1350f1ae32a1SGerd Hoffmann static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) 1351f1ae32a1SGerd Hoffmann { 1352f1ae32a1SGerd Hoffmann val &= OHCI_FMI_FI; 1353f1ae32a1SGerd Hoffmann 1354f1ae32a1SGerd Hoffmann if (val != ohci->fi) { 1355dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi); 1356f1ae32a1SGerd Hoffmann } 1357f1ae32a1SGerd Hoffmann 1358f1ae32a1SGerd Hoffmann ohci->fi = val; 1359f1ae32a1SGerd Hoffmann } 1360f1ae32a1SGerd Hoffmann 1361f1ae32a1SGerd Hoffmann static void ohci_port_power(OHCIState *ohci, int i, int p) 1362f1ae32a1SGerd Hoffmann { 1363f1ae32a1SGerd Hoffmann if (p) { 1364f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_PPS; 1365f1ae32a1SGerd Hoffmann } else { 1366f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| 1367f1ae32a1SGerd Hoffmann OHCI_PORT_CCS| 1368f1ae32a1SGerd Hoffmann OHCI_PORT_PSS| 1369f1ae32a1SGerd Hoffmann OHCI_PORT_PRS); 1370f1ae32a1SGerd Hoffmann } 1371f1ae32a1SGerd Hoffmann } 1372f1ae32a1SGerd Hoffmann 1373f1ae32a1SGerd Hoffmann /* Set HcControlRegister */ 1374f1ae32a1SGerd Hoffmann static void ohci_set_ctl(OHCIState *ohci, uint32_t val) 1375f1ae32a1SGerd Hoffmann { 1376f1ae32a1SGerd Hoffmann uint32_t old_state; 1377f1ae32a1SGerd Hoffmann uint32_t new_state; 1378f1ae32a1SGerd Hoffmann 1379f1ae32a1SGerd Hoffmann old_state = ohci->ctl & OHCI_CTL_HCFS; 1380f1ae32a1SGerd Hoffmann ohci->ctl = val; 1381f1ae32a1SGerd Hoffmann new_state = ohci->ctl & OHCI_CTL_HCFS; 1382f1ae32a1SGerd Hoffmann 1383f1ae32a1SGerd Hoffmann /* no state change */ 1384f1ae32a1SGerd Hoffmann if (old_state == new_state) 1385f1ae32a1SGerd Hoffmann return; 1386f1ae32a1SGerd Hoffmann 1387dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_ctl(ohci->name, new_state); 1388f1ae32a1SGerd Hoffmann switch (new_state) { 1389f1ae32a1SGerd Hoffmann case OHCI_USB_OPERATIONAL: 1390f1ae32a1SGerd Hoffmann ohci_bus_start(ohci); 1391f1ae32a1SGerd Hoffmann break; 1392f1ae32a1SGerd Hoffmann case OHCI_USB_SUSPEND: 1393f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 1394087462c7SLaurent Vivier /* clear pending SF otherwise linux driver loops in ohci_irq() */ 1395087462c7SLaurent Vivier ohci->intr_status &= ~OHCI_INTR_SF; 1396087462c7SLaurent Vivier ohci_intr_update(ohci); 1397f1ae32a1SGerd Hoffmann break; 1398f1ae32a1SGerd Hoffmann case OHCI_USB_RESUME: 1399dc1f5988SAlexey Kardashevskiy trace_usb_ohci_resume(ohci->name); 1400f1ae32a1SGerd Hoffmann break; 1401f1ae32a1SGerd Hoffmann case OHCI_USB_RESET: 14027d938fd1SHervé Poussineau ohci_roothub_reset(ohci); 1403f1ae32a1SGerd Hoffmann break; 1404f1ae32a1SGerd Hoffmann } 1405f1ae32a1SGerd Hoffmann } 1406f1ae32a1SGerd Hoffmann 1407f1ae32a1SGerd Hoffmann static uint32_t ohci_get_frame_remaining(OHCIState *ohci) 1408f1ae32a1SGerd Hoffmann { 1409f1ae32a1SGerd Hoffmann uint16_t fr; 1410f1ae32a1SGerd Hoffmann int64_t tks; 1411f1ae32a1SGerd Hoffmann 1412f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) 1413f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1414f1ae32a1SGerd Hoffmann 1415f1ae32a1SGerd Hoffmann /* Being in USB operational state guarnatees sof_time was 1416f1ae32a1SGerd Hoffmann * set already. 1417f1ae32a1SGerd Hoffmann */ 1418bc72ad67SAlex Bligh tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time; 1419a60f39a4SMiguel GAIO if (tks < 0) { 1420a60f39a4SMiguel GAIO tks = 0; 1421a60f39a4SMiguel GAIO } 1422f1ae32a1SGerd Hoffmann 1423f1ae32a1SGerd Hoffmann /* avoid muldiv if possible */ 1424f1ae32a1SGerd Hoffmann if (tks >= usb_frame_time) 1425f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1426f1ae32a1SGerd Hoffmann 1427cd1f16f9SLaurent Vivier tks = tks / usb_bit_time; 1428f1ae32a1SGerd Hoffmann fr = (uint16_t)(ohci->fi - tks); 1429f1ae32a1SGerd Hoffmann 1430f1ae32a1SGerd Hoffmann return (ohci->frt << 31) | fr; 1431f1ae32a1SGerd Hoffmann } 1432f1ae32a1SGerd Hoffmann 1433f1ae32a1SGerd Hoffmann 1434f1ae32a1SGerd Hoffmann /* Set root hub status */ 1435f1ae32a1SGerd Hoffmann static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) 1436f1ae32a1SGerd Hoffmann { 1437f1ae32a1SGerd Hoffmann uint32_t old_state; 1438f1ae32a1SGerd Hoffmann 1439f1ae32a1SGerd Hoffmann old_state = ohci->rhstatus; 1440f1ae32a1SGerd Hoffmann 1441f1ae32a1SGerd Hoffmann /* write 1 to clear OCIC */ 1442f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_OCIC) 1443f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_OCIC; 1444f1ae32a1SGerd Hoffmann 1445f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPS) { 1446f1ae32a1SGerd Hoffmann int i; 1447f1ae32a1SGerd Hoffmann 1448f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1449f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 0); 1450dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_down(); 1451f1ae32a1SGerd Hoffmann } 1452f1ae32a1SGerd Hoffmann 1453f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPSC) { 1454f1ae32a1SGerd Hoffmann int i; 1455f1ae32a1SGerd Hoffmann 1456f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1457f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 1); 1458dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_up(); 1459f1ae32a1SGerd Hoffmann } 1460f1ae32a1SGerd Hoffmann 1461f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_DRWE) 1462f1ae32a1SGerd Hoffmann ohci->rhstatus |= OHCI_RHS_DRWE; 1463f1ae32a1SGerd Hoffmann 1464f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_CRWE) 1465f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_DRWE; 1466f1ae32a1SGerd Hoffmann 1467f1ae32a1SGerd Hoffmann if (old_state != ohci->rhstatus) 1468f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1469f1ae32a1SGerd Hoffmann } 1470f1ae32a1SGerd Hoffmann 1471f1ae32a1SGerd Hoffmann /* Set root hub port status */ 1472f1ae32a1SGerd Hoffmann static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) 1473f1ae32a1SGerd Hoffmann { 1474f1ae32a1SGerd Hoffmann uint32_t old_state; 1475f1ae32a1SGerd Hoffmann OHCIPort *port; 1476f1ae32a1SGerd Hoffmann 1477f1ae32a1SGerd Hoffmann port = &ohci->rhport[portnum]; 1478f1ae32a1SGerd Hoffmann old_state = port->ctrl; 1479f1ae32a1SGerd Hoffmann 1480f1ae32a1SGerd Hoffmann /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ 1481f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_WTC) 1482f1ae32a1SGerd Hoffmann port->ctrl &= ~(val & OHCI_PORT_WTC); 1483f1ae32a1SGerd Hoffmann 1484f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_CCS) 1485f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 1486f1ae32a1SGerd Hoffmann 1487f1ae32a1SGerd Hoffmann ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); 1488f1ae32a1SGerd Hoffmann 1489f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) { 1490dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_suspend(portnum); 1491f1ae32a1SGerd Hoffmann } 1492f1ae32a1SGerd Hoffmann 1493f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { 1494dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_reset(portnum); 1495f1ae32a1SGerd Hoffmann usb_device_reset(port->port.dev); 1496f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PRS; 1497f1ae32a1SGerd Hoffmann /* ??? Should this also set OHCI_PORT_PESC. */ 1498f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; 1499f1ae32a1SGerd Hoffmann } 1500f1ae32a1SGerd Hoffmann 1501f1ae32a1SGerd Hoffmann /* Invert order here to ensure in ambiguous case, device is 1502f1ae32a1SGerd Hoffmann * powered up... 1503f1ae32a1SGerd Hoffmann */ 1504f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_LSDA) 1505f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 0); 1506f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_PPS) 1507f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 1); 1508f1ae32a1SGerd Hoffmann 1509f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) 1510f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1511f1ae32a1SGerd Hoffmann } 1512f1ae32a1SGerd Hoffmann 1513f1ae32a1SGerd Hoffmann static uint64_t ohci_mem_read(void *opaque, 1514a8170e5eSAvi Kivity hwaddr addr, 1515f1ae32a1SGerd Hoffmann unsigned size) 1516f1ae32a1SGerd Hoffmann { 1517f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1518f1ae32a1SGerd Hoffmann uint32_t retval; 1519f1ae32a1SGerd Hoffmann 1520f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1521f1ae32a1SGerd Hoffmann if (addr & 3) { 1522dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_unaligned(addr); 1523f1ae32a1SGerd Hoffmann return 0xffffffff; 1524f1ae32a1SGerd Hoffmann } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1525f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1526f1ae32a1SGerd Hoffmann retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; 1527f1ae32a1SGerd Hoffmann } else { 1528f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1529f1ae32a1SGerd Hoffmann case 0: /* HcRevision */ 1530f1ae32a1SGerd Hoffmann retval = 0x10; 1531f1ae32a1SGerd Hoffmann break; 1532f1ae32a1SGerd Hoffmann 1533f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1534f1ae32a1SGerd Hoffmann retval = ohci->ctl; 1535f1ae32a1SGerd Hoffmann break; 1536f1ae32a1SGerd Hoffmann 1537f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1538f1ae32a1SGerd Hoffmann retval = ohci->status; 1539f1ae32a1SGerd Hoffmann break; 1540f1ae32a1SGerd Hoffmann 1541f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1542f1ae32a1SGerd Hoffmann retval = ohci->intr_status; 1543f1ae32a1SGerd Hoffmann break; 1544f1ae32a1SGerd Hoffmann 1545f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1546f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1547f1ae32a1SGerd Hoffmann retval = ohci->intr; 1548f1ae32a1SGerd Hoffmann break; 1549f1ae32a1SGerd Hoffmann 1550f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1551f1ae32a1SGerd Hoffmann retval = ohci->hcca; 1552f1ae32a1SGerd Hoffmann break; 1553f1ae32a1SGerd Hoffmann 1554f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1555f1ae32a1SGerd Hoffmann retval = ohci->per_cur; 1556f1ae32a1SGerd Hoffmann break; 1557f1ae32a1SGerd Hoffmann 1558f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1559f1ae32a1SGerd Hoffmann retval = ohci->ctrl_head; 1560f1ae32a1SGerd Hoffmann break; 1561f1ae32a1SGerd Hoffmann 1562f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1563f1ae32a1SGerd Hoffmann retval = ohci->ctrl_cur; 1564f1ae32a1SGerd Hoffmann break; 1565f1ae32a1SGerd Hoffmann 1566f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1567f1ae32a1SGerd Hoffmann retval = ohci->bulk_head; 1568f1ae32a1SGerd Hoffmann break; 1569f1ae32a1SGerd Hoffmann 1570f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1571f1ae32a1SGerd Hoffmann retval = ohci->bulk_cur; 1572f1ae32a1SGerd Hoffmann break; 1573f1ae32a1SGerd Hoffmann 1574f1ae32a1SGerd Hoffmann case 12: /* HcDoneHead */ 1575f1ae32a1SGerd Hoffmann retval = ohci->done; 1576f1ae32a1SGerd Hoffmann break; 1577f1ae32a1SGerd Hoffmann 1578f1ae32a1SGerd Hoffmann case 13: /* HcFmInterretval */ 1579f1ae32a1SGerd Hoffmann retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); 1580f1ae32a1SGerd Hoffmann break; 1581f1ae32a1SGerd Hoffmann 1582f1ae32a1SGerd Hoffmann case 14: /* HcFmRemaining */ 1583f1ae32a1SGerd Hoffmann retval = ohci_get_frame_remaining(ohci); 1584f1ae32a1SGerd Hoffmann break; 1585f1ae32a1SGerd Hoffmann 1586f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1587f1ae32a1SGerd Hoffmann retval = ohci->frame_number; 1588f1ae32a1SGerd Hoffmann break; 1589f1ae32a1SGerd Hoffmann 1590f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1591f1ae32a1SGerd Hoffmann retval = ohci->pstart; 1592f1ae32a1SGerd Hoffmann break; 1593f1ae32a1SGerd Hoffmann 1594f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1595f1ae32a1SGerd Hoffmann retval = ohci->lst; 1596f1ae32a1SGerd Hoffmann break; 1597f1ae32a1SGerd Hoffmann 1598f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1599f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_a; 1600f1ae32a1SGerd Hoffmann break; 1601f1ae32a1SGerd Hoffmann 1602f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1603f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_b; 1604f1ae32a1SGerd Hoffmann break; 1605f1ae32a1SGerd Hoffmann 1606f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1607f1ae32a1SGerd Hoffmann retval = ohci->rhstatus; 1608f1ae32a1SGerd Hoffmann break; 1609f1ae32a1SGerd Hoffmann 1610f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1611f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1612f1ae32a1SGerd Hoffmann retval = ohci->hstatus & ohci->hmask; 1613f1ae32a1SGerd Hoffmann break; 1614f1ae32a1SGerd Hoffmann 1615f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1616f1ae32a1SGerd Hoffmann retval = ohci->hreset; 1617f1ae32a1SGerd Hoffmann break; 1618f1ae32a1SGerd Hoffmann 1619f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1620f1ae32a1SGerd Hoffmann retval = ohci->hmask; 1621f1ae32a1SGerd Hoffmann break; 1622f1ae32a1SGerd Hoffmann 1623f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1624f1ae32a1SGerd Hoffmann retval = ohci->htest; 1625f1ae32a1SGerd Hoffmann break; 1626f1ae32a1SGerd Hoffmann 1627f1ae32a1SGerd Hoffmann default: 1628dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_bad_offset(addr); 1629f1ae32a1SGerd Hoffmann retval = 0xffffffff; 1630f1ae32a1SGerd Hoffmann } 1631f1ae32a1SGerd Hoffmann } 1632f1ae32a1SGerd Hoffmann 1633f1ae32a1SGerd Hoffmann return retval; 1634f1ae32a1SGerd Hoffmann } 1635f1ae32a1SGerd Hoffmann 1636f1ae32a1SGerd Hoffmann static void ohci_mem_write(void *opaque, 1637a8170e5eSAvi Kivity hwaddr addr, 1638f1ae32a1SGerd Hoffmann uint64_t val, 1639f1ae32a1SGerd Hoffmann unsigned size) 1640f1ae32a1SGerd Hoffmann { 1641f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1642f1ae32a1SGerd Hoffmann 1643f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1644f1ae32a1SGerd Hoffmann if (addr & 3) { 1645dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_unaligned(addr); 1646f1ae32a1SGerd Hoffmann return; 1647f1ae32a1SGerd Hoffmann } 1648f1ae32a1SGerd Hoffmann 1649f1ae32a1SGerd Hoffmann if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1650f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1651f1ae32a1SGerd Hoffmann ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); 1652f1ae32a1SGerd Hoffmann return; 1653f1ae32a1SGerd Hoffmann } 1654f1ae32a1SGerd Hoffmann 1655f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1656f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1657f1ae32a1SGerd Hoffmann ohci_set_ctl(ohci, val); 1658f1ae32a1SGerd Hoffmann break; 1659f1ae32a1SGerd Hoffmann 1660f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1661f1ae32a1SGerd Hoffmann /* SOC is read-only */ 1662f1ae32a1SGerd Hoffmann val = (val & ~OHCI_STATUS_SOC); 1663f1ae32a1SGerd Hoffmann 1664f1ae32a1SGerd Hoffmann /* Bits written as '0' remain unchanged in the register */ 1665f1ae32a1SGerd Hoffmann ohci->status |= val; 1666f1ae32a1SGerd Hoffmann 1667f1ae32a1SGerd Hoffmann if (ohci->status & OHCI_STATUS_HCR) 16680922c3f6SHervé Poussineau ohci_soft_reset(ohci); 1669f1ae32a1SGerd Hoffmann break; 1670f1ae32a1SGerd Hoffmann 1671f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1672f1ae32a1SGerd Hoffmann ohci->intr_status &= ~val; 1673f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1674f1ae32a1SGerd Hoffmann break; 1675f1ae32a1SGerd Hoffmann 1676f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1677f1ae32a1SGerd Hoffmann ohci->intr |= val; 1678f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1679f1ae32a1SGerd Hoffmann break; 1680f1ae32a1SGerd Hoffmann 1681f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1682f1ae32a1SGerd Hoffmann ohci->intr &= ~val; 1683f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1684f1ae32a1SGerd Hoffmann break; 1685f1ae32a1SGerd Hoffmann 1686f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1687f1ae32a1SGerd Hoffmann ohci->hcca = val & OHCI_HCCA_MASK; 1688f1ae32a1SGerd Hoffmann break; 1689f1ae32a1SGerd Hoffmann 1690f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1691f1ae32a1SGerd Hoffmann /* Ignore writes to this read-only register, Linux does them */ 1692f1ae32a1SGerd Hoffmann break; 1693f1ae32a1SGerd Hoffmann 1694f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1695f1ae32a1SGerd Hoffmann ohci->ctrl_head = val & OHCI_EDPTR_MASK; 1696f1ae32a1SGerd Hoffmann break; 1697f1ae32a1SGerd Hoffmann 1698f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1699f1ae32a1SGerd Hoffmann ohci->ctrl_cur = val & OHCI_EDPTR_MASK; 1700f1ae32a1SGerd Hoffmann break; 1701f1ae32a1SGerd Hoffmann 1702f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1703f1ae32a1SGerd Hoffmann ohci->bulk_head = val & OHCI_EDPTR_MASK; 1704f1ae32a1SGerd Hoffmann break; 1705f1ae32a1SGerd Hoffmann 1706f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1707f1ae32a1SGerd Hoffmann ohci->bulk_cur = val & OHCI_EDPTR_MASK; 1708f1ae32a1SGerd Hoffmann break; 1709f1ae32a1SGerd Hoffmann 1710f1ae32a1SGerd Hoffmann case 13: /* HcFmInterval */ 1711f1ae32a1SGerd Hoffmann ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; 1712f1ae32a1SGerd Hoffmann ohci->fit = (val & OHCI_FMI_FIT) >> 31; 1713f1ae32a1SGerd Hoffmann ohci_set_frame_interval(ohci, val); 1714f1ae32a1SGerd Hoffmann break; 1715f1ae32a1SGerd Hoffmann 1716f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1717f1ae32a1SGerd Hoffmann break; 1718f1ae32a1SGerd Hoffmann 1719f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1720f1ae32a1SGerd Hoffmann ohci->pstart = val & 0xffff; 1721f1ae32a1SGerd Hoffmann break; 1722f1ae32a1SGerd Hoffmann 1723f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1724f1ae32a1SGerd Hoffmann ohci->lst = val & 0xffff; 1725f1ae32a1SGerd Hoffmann break; 1726f1ae32a1SGerd Hoffmann 1727f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1728f1ae32a1SGerd Hoffmann ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; 1729f1ae32a1SGerd Hoffmann ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; 1730f1ae32a1SGerd Hoffmann break; 1731f1ae32a1SGerd Hoffmann 1732f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1733f1ae32a1SGerd Hoffmann break; 1734f1ae32a1SGerd Hoffmann 1735f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1736f1ae32a1SGerd Hoffmann ohci_set_hub_status(ohci, val); 1737f1ae32a1SGerd Hoffmann break; 1738f1ae32a1SGerd Hoffmann 1739f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1740f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1741f1ae32a1SGerd Hoffmann ohci->hstatus &= ~(val & ohci->hmask); 17427fa96d73SGerd Hoffmann break; 1743f1ae32a1SGerd Hoffmann 1744f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1745f1ae32a1SGerd Hoffmann ohci->hreset = val & ~OHCI_HRESET_FSBIR; 1746f1ae32a1SGerd Hoffmann if (val & OHCI_HRESET_FSBIR) 174784d04e21SHervé Poussineau ohci_hard_reset(ohci); 1748f1ae32a1SGerd Hoffmann break; 1749f1ae32a1SGerd Hoffmann 1750f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1751f1ae32a1SGerd Hoffmann ohci->hmask = val; 1752f1ae32a1SGerd Hoffmann break; 1753f1ae32a1SGerd Hoffmann 1754f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1755f1ae32a1SGerd Hoffmann ohci->htest = val; 1756f1ae32a1SGerd Hoffmann break; 1757f1ae32a1SGerd Hoffmann 1758f1ae32a1SGerd Hoffmann default: 1759dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_bad_offset(addr); 1760f1ae32a1SGerd Hoffmann break; 1761f1ae32a1SGerd Hoffmann } 1762f1ae32a1SGerd Hoffmann } 1763f1ae32a1SGerd Hoffmann 1764f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev) 1765f1ae32a1SGerd Hoffmann { 1766f1ae32a1SGerd Hoffmann if (ohci->async_td && 1767f1ae32a1SGerd Hoffmann usb_packet_is_inflight(&ohci->usb_packet) && 1768f1ae32a1SGerd Hoffmann ohci->usb_packet.ep->dev == dev) { 1769f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1770f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1771f1ae32a1SGerd Hoffmann } 1772f1ae32a1SGerd Hoffmann } 1773f1ae32a1SGerd Hoffmann 1774f1ae32a1SGerd Hoffmann static const MemoryRegionOps ohci_mem_ops = { 1775f1ae32a1SGerd Hoffmann .read = ohci_mem_read, 1776f1ae32a1SGerd Hoffmann .write = ohci_mem_write, 1777f1ae32a1SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 1778f1ae32a1SGerd Hoffmann }; 1779f1ae32a1SGerd Hoffmann 1780f1ae32a1SGerd Hoffmann static USBPortOps ohci_port_ops = { 1781f1ae32a1SGerd Hoffmann .attach = ohci_attach, 1782f1ae32a1SGerd Hoffmann .detach = ohci_detach, 1783f1ae32a1SGerd Hoffmann .child_detach = ohci_child_detach, 1784f1ae32a1SGerd Hoffmann .wakeup = ohci_wakeup, 1785f1ae32a1SGerd Hoffmann .complete = ohci_async_complete_packet, 1786f1ae32a1SGerd Hoffmann }; 1787f1ae32a1SGerd Hoffmann 1788f1ae32a1SGerd Hoffmann static USBBusOps ohci_bus_ops = { 1789f1ae32a1SGerd Hoffmann }; 1790f1ae32a1SGerd Hoffmann 179134d97308SThomas Huth void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports, 179234d97308SThomas Huth dma_addr_t localmem_base, char *masterbus, 179334d97308SThomas Huth uint32_t firstport, AddressSpace *as, 179472e0c127SThomas Huth void (*ohci_die_fn)(struct OHCIState *), Error **errp) 1795f1ae32a1SGerd Hoffmann { 1796f4bbaaf5SMarkus Armbruster Error *err = NULL; 1797f1ae32a1SGerd Hoffmann int i; 1798f1ae32a1SGerd Hoffmann 1799df32fd1cSPaolo Bonzini ohci->as = as; 180072e0c127SThomas Huth ohci->ohci_die = ohci_die_fn; 18019ac6a217SDavid Gibson 1802d400fc01SThomas Huth if (num_ports > OHCI_MAX_PORTS) { 1803b9a3a4f2SLi Qiang error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)", 1804d400fc01SThomas Huth num_ports, OHCI_MAX_PORTS); 1805d400fc01SThomas Huth return; 1806d400fc01SThomas Huth } 1807d400fc01SThomas Huth 1808f1ae32a1SGerd Hoffmann if (usb_frame_time == 0) { 1809f1ae32a1SGerd Hoffmann #ifdef OHCI_TIME_WARP 181073bcb24dSRutuja Shah usb_frame_time = NANOSECONDS_PER_SECOND; 181173bcb24dSRutuja Shah usb_bit_time = NANOSECONDS_PER_SECOND / (USB_HZ / 1000); 1812f1ae32a1SGerd Hoffmann #else 181373bcb24dSRutuja Shah usb_frame_time = NANOSECONDS_PER_SECOND / 1000; 181473bcb24dSRutuja Shah if (NANOSECONDS_PER_SECOND >= USB_HZ) { 181573bcb24dSRutuja Shah usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ; 1816f1ae32a1SGerd Hoffmann } else { 1817f1ae32a1SGerd Hoffmann usb_bit_time = 1; 1818f1ae32a1SGerd Hoffmann } 1819f1ae32a1SGerd Hoffmann #endif 1820dc1f5988SAlexey Kardashevskiy trace_usb_ohci_init_time(usb_frame_time, usb_bit_time); 1821f1ae32a1SGerd Hoffmann } 1822f1ae32a1SGerd Hoffmann 1823f1ae32a1SGerd Hoffmann ohci->num_ports = num_ports; 1824f1ae32a1SGerd Hoffmann if (masterbus) { 1825f1ae32a1SGerd Hoffmann USBPort *ports[OHCI_MAX_PORTS]; 1826f1ae32a1SGerd Hoffmann for(i = 0; i < num_ports; i++) { 1827f1ae32a1SGerd Hoffmann ports[i] = &ohci->rhport[i].port; 1828f1ae32a1SGerd Hoffmann } 1829f4bbaaf5SMarkus Armbruster usb_register_companion(masterbus, ports, num_ports, 1830f1ae32a1SGerd Hoffmann firstport, ohci, &ohci_port_ops, 1831f4bbaaf5SMarkus Armbruster USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, 1832f4bbaaf5SMarkus Armbruster &err); 1833f4bbaaf5SMarkus Armbruster if (err) { 183487581feaSMarkus Armbruster error_propagate(errp, err); 183587581feaSMarkus Armbruster return; 1836f1ae32a1SGerd Hoffmann } 1837f1ae32a1SGerd Hoffmann } else { 1838c889b3a5SAndreas Färber usb_bus_new(&ohci->bus, sizeof(ohci->bus), &ohci_bus_ops, dev); 1839f1ae32a1SGerd Hoffmann for (i = 0; i < num_ports; i++) { 1840f1ae32a1SGerd Hoffmann usb_register_port(&ohci->bus, &ohci->rhport[i].port, 1841f1ae32a1SGerd Hoffmann ohci, i, &ohci_port_ops, 1842f1ae32a1SGerd Hoffmann USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); 1843f1ae32a1SGerd Hoffmann } 1844f1ae32a1SGerd Hoffmann } 1845f1ae32a1SGerd Hoffmann 184622fc860bSPaolo Bonzini memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops, 184722fc860bSPaolo Bonzini ohci, "ohci", 256); 1848f1ae32a1SGerd Hoffmann ohci->localmem_base = localmem_base; 1849f1ae32a1SGerd Hoffmann 1850f1ae32a1SGerd Hoffmann ohci->name = object_get_typename(OBJECT(dev)); 1851f1ae32a1SGerd Hoffmann usb_packet_init(&ohci->usb_packet); 1852f1ae32a1SGerd Hoffmann 1853f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1854fa1298c2SGerd Hoffmann 1855fa1298c2SGerd Hoffmann ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1856fa1298c2SGerd Hoffmann ohci_frame_boundary, ohci); 1857f1ae32a1SGerd Hoffmann } 1858f1ae32a1SGerd Hoffmann 185972e0c127SThomas Huth /** 186072e0c127SThomas Huth * A typical OHCI will stop operating and set itself into error state 186172e0c127SThomas Huth * (which can be queried by MMIO) to signal that it got an error. 1862cf66ee8eSAlexey Kardashevskiy */ 186334d97308SThomas Huth void ohci_sysbus_die(struct OHCIState *ohci) 1864cf66ee8eSAlexey Kardashevskiy { 1865dc1f5988SAlexey Kardashevskiy trace_usb_ohci_die(); 1866cf66ee8eSAlexey Kardashevskiy 1867cf66ee8eSAlexey Kardashevskiy ohci_set_interrupt(ohci, OHCI_INTR_UE); 1868cf66ee8eSAlexey Kardashevskiy ohci_bus_stop(ohci); 186972e0c127SThomas Huth } 187072e0c127SThomas Huth 18711aa0c0c7SHu Tao #define TYPE_SYSBUS_OHCI "sysbus-ohci" 18721aa0c0c7SHu Tao #define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI) 18731aa0c0c7SHu Tao 1874f1ae32a1SGerd Hoffmann typedef struct { 18751aa0c0c7SHu Tao /*< private >*/ 18761aa0c0c7SHu Tao SysBusDevice parent_obj; 18771aa0c0c7SHu Tao /*< public >*/ 18781aa0c0c7SHu Tao 1879f1ae32a1SGerd Hoffmann OHCIState ohci; 1880d7145b66SBALATON Zoltan char *masterbus; 1881f1ae32a1SGerd Hoffmann uint32_t num_ports; 1882d7145b66SBALATON Zoltan uint32_t firstport; 18839ac6a217SDavid Gibson dma_addr_t dma_offset; 1884f1ae32a1SGerd Hoffmann } OHCISysBusState; 1885f1ae32a1SGerd Hoffmann 1886457215ecSHu Tao static void ohci_realize_pxa(DeviceState *dev, Error **errp) 1887f1ae32a1SGerd Hoffmann { 18881aa0c0c7SHu Tao OHCISysBusState *s = SYSBUS_OHCI(dev); 1889457215ecSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 1890d7145b66SBALATON Zoltan Error *err = NULL; 1891f1ae32a1SGerd Hoffmann 1892d7145b66SBALATON Zoltan usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, 1893d7145b66SBALATON Zoltan s->masterbus, s->firstport, 189472e0c127SThomas Huth &address_space_memory, ohci_sysbus_die, &err); 1895d7145b66SBALATON Zoltan if (err) { 1896d7145b66SBALATON Zoltan error_propagate(errp, err); 1897d7145b66SBALATON Zoltan return; 1898d7145b66SBALATON Zoltan } 1899457215ecSHu Tao sysbus_init_irq(sbd, &s->ohci.irq); 1900457215ecSHu Tao sysbus_init_mmio(sbd, &s->ohci.mem); 1901f1ae32a1SGerd Hoffmann } 1902f1ae32a1SGerd Hoffmann 190388dd1b8dSGonglei static void usb_ohci_reset_sysbus(DeviceState *dev) 190488dd1b8dSGonglei { 190588dd1b8dSGonglei OHCISysBusState *s = SYSBUS_OHCI(dev); 190688dd1b8dSGonglei OHCIState *ohci = &s->ohci; 190788dd1b8dSGonglei 190884d04e21SHervé Poussineau ohci_hard_reset(ohci); 190988dd1b8dSGonglei } 191088dd1b8dSGonglei 191169e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_state_port = { 191269e25d26SAlexey Kardashevskiy .name = "ohci-core/port", 191369e25d26SAlexey Kardashevskiy .version_id = 1, 191469e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 191569e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 191669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl, OHCIPort), 191769e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 191869e25d26SAlexey Kardashevskiy }, 191969e25d26SAlexey Kardashevskiy }; 192069e25d26SAlexey Kardashevskiy 192169e25d26SAlexey Kardashevskiy static bool ohci_eof_timer_needed(void *opaque) 192269e25d26SAlexey Kardashevskiy { 192369e25d26SAlexey Kardashevskiy OHCIState *ohci = opaque; 192469e25d26SAlexey Kardashevskiy 1925fa1298c2SGerd Hoffmann return timer_pending(ohci->eof_timer); 192669e25d26SAlexey Kardashevskiy } 192769e25d26SAlexey Kardashevskiy 192869e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_eof_timer = { 192969e25d26SAlexey Kardashevskiy .name = "ohci-core/eof-timer", 193069e25d26SAlexey Kardashevskiy .version_id = 1, 193169e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 19325cd8cadaSJuan Quintela .needed = ohci_eof_timer_needed, 193369e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 1934e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(eof_timer, OHCIState), 193569e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 193669e25d26SAlexey Kardashevskiy }, 193769e25d26SAlexey Kardashevskiy }; 193869e25d26SAlexey Kardashevskiy 193934d97308SThomas Huth const VMStateDescription vmstate_ohci_state = { 194069e25d26SAlexey Kardashevskiy .name = "ohci-core", 194169e25d26SAlexey Kardashevskiy .version_id = 1, 194269e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 194369e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 194469e25d26SAlexey Kardashevskiy VMSTATE_INT64(sof_time, OHCIState), 194569e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctl, OHCIState), 194669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(status, OHCIState), 194769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr_status, OHCIState), 194869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr, OHCIState), 194969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hcca, OHCIState), 195069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_head, OHCIState), 195169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_cur, OHCIState), 195269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_head, OHCIState), 195369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_cur, OHCIState), 195469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(per_cur, OHCIState), 195569e25d26SAlexey Kardashevskiy VMSTATE_UINT32(done, OHCIState), 195669e25d26SAlexey Kardashevskiy VMSTATE_INT32(done_count, OHCIState), 195769e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fsmps, OHCIState), 195869e25d26SAlexey Kardashevskiy VMSTATE_UINT8(fit, OHCIState), 195969e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fi, OHCIState), 196069e25d26SAlexey Kardashevskiy VMSTATE_UINT8(frt, OHCIState), 196169e25d26SAlexey Kardashevskiy VMSTATE_UINT16(frame_number, OHCIState), 196269e25d26SAlexey Kardashevskiy VMSTATE_UINT16(padding, OHCIState), 196369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(pstart, OHCIState), 196469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(lst, OHCIState), 196569e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_a, OHCIState), 196669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_b, OHCIState), 196769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhstatus, OHCIState), 196869e25d26SAlexey Kardashevskiy VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0, 196969e25d26SAlexey Kardashevskiy vmstate_ohci_state_port, OHCIPort), 197069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hstatus, OHCIState), 197169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hmask, OHCIState), 197269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hreset, OHCIState), 197369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(htest, OHCIState), 197469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(old_ctl, OHCIState), 197569e25d26SAlexey Kardashevskiy VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192), 197669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(async_td, OHCIState), 197769e25d26SAlexey Kardashevskiy VMSTATE_BOOL(async_complete, OHCIState), 197869e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 197969e25d26SAlexey Kardashevskiy }, 19805cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 19815cd8cadaSJuan Quintela &vmstate_ohci_eof_timer, 19825cd8cadaSJuan Quintela NULL 198369e25d26SAlexey Kardashevskiy } 198469e25d26SAlexey Kardashevskiy }; 198569e25d26SAlexey Kardashevskiy 1986f1ae32a1SGerd Hoffmann static Property ohci_sysbus_properties[] = { 1987d7145b66SBALATON Zoltan DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus), 1988f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), 1989d7145b66SBALATON Zoltan DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0), 19906998b6c7SVijay Kumar B DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0), 1991f1ae32a1SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 1992f1ae32a1SGerd Hoffmann }; 1993f1ae32a1SGerd Hoffmann 1994f1ae32a1SGerd Hoffmann static void ohci_sysbus_class_init(ObjectClass *klass, void *data) 1995f1ae32a1SGerd Hoffmann { 1996f1ae32a1SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 1997f1ae32a1SGerd Hoffmann 1998457215ecSHu Tao dc->realize = ohci_realize_pxa; 1999125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_USB, dc->categories); 2000f1ae32a1SGerd Hoffmann dc->desc = "OHCI USB Controller"; 2001f1ae32a1SGerd Hoffmann dc->props = ohci_sysbus_properties; 200288dd1b8dSGonglei dc->reset = usb_ohci_reset_sysbus; 2003f1ae32a1SGerd Hoffmann } 2004f1ae32a1SGerd Hoffmann 20058c43a6f0SAndreas Färber static const TypeInfo ohci_sysbus_info = { 20061aa0c0c7SHu Tao .name = TYPE_SYSBUS_OHCI, 2007f1ae32a1SGerd Hoffmann .parent = TYPE_SYS_BUS_DEVICE, 2008f1ae32a1SGerd Hoffmann .instance_size = sizeof(OHCISysBusState), 2009f1ae32a1SGerd Hoffmann .class_init = ohci_sysbus_class_init, 2010f1ae32a1SGerd Hoffmann }; 2011f1ae32a1SGerd Hoffmann 2012f1ae32a1SGerd Hoffmann static void ohci_register_types(void) 2013f1ae32a1SGerd Hoffmann { 2014f1ae32a1SGerd Hoffmann type_register_static(&ohci_sysbus_info); 2015f1ae32a1SGerd Hoffmann } 2016f1ae32a1SGerd Hoffmann 2017f1ae32a1SGerd Hoffmann type_init(ohci_register_types) 2018