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 10bee41971SChetan Pant * version 2.1 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" 2964552b6bSMarkus Armbruster #include "hw/irq.h" 30da34e65cSMarkus Armbruster #include "qapi/error.h" 310b8fa32fSMarkus Armbruster #include "qemu/module.h" 321de7afc9SPaolo Bonzini #include "qemu/timer.h" 33f1ae32a1SGerd Hoffmann #include "hw/usb.h" 34d6454270SMarkus Armbruster #include "migration/vmstate.h" 35f1ae32a1SGerd Hoffmann #include "hw/sysbus.h" 369ac6a217SDavid Gibson #include "hw/qdev-dma.h" 37a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 38dc1f5988SAlexey Kardashevskiy #include "trace.h" 3934d97308SThomas Huth #include "hcd-ohci.h" 40f1ae32a1SGerd Hoffmann 41f1ae32a1SGerd Hoffmann /* This causes frames to occur 1000x slower */ 42f1ae32a1SGerd Hoffmann //#define OHCI_TIME_WARP 1 43f1ae32a1SGerd Hoffmann 44ab6b1105SGerd Hoffmann #define ED_LINK_LIMIT 32 4595ed5693SLi Qiang 46f1ae32a1SGerd Hoffmann static int64_t usb_frame_time; 47f1ae32a1SGerd Hoffmann static int64_t usb_bit_time; 48f1ae32a1SGerd Hoffmann 49f1ae32a1SGerd Hoffmann /* Host Controller Communications Area */ 50f1ae32a1SGerd Hoffmann struct ohci_hcca { 51f1ae32a1SGerd Hoffmann uint32_t intr[32]; 52f1ae32a1SGerd Hoffmann uint16_t frame, pad; 53f1ae32a1SGerd Hoffmann uint32_t done; 54f1ae32a1SGerd Hoffmann }; 5586e18caeSWei Yang #define HCCA_WRITEBACK_OFFSET offsetof(struct ohci_hcca, frame) 5686e18caeSWei Yang #define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */ 5786e18caeSWei Yang 5886e18caeSWei Yang #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head) 5986e18caeSWei Yang #define ED_WBACK_SIZE 4 60f1ae32a1SGerd Hoffmann 61f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); 62f1ae32a1SGerd Hoffmann 63f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Endpoint Desciptor. */ 64f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_SHIFT 0 65f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT) 66f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_SHIFT 7 67f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT) 68f1ae32a1SGerd Hoffmann #define OHCI_ED_D_SHIFT 11 69f1ae32a1SGerd Hoffmann #define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT) 70f1ae32a1SGerd Hoffmann #define OHCI_ED_S (1<<13) 71f1ae32a1SGerd Hoffmann #define OHCI_ED_K (1<<14) 72f1ae32a1SGerd Hoffmann #define OHCI_ED_F (1<<15) 73f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_SHIFT 16 74f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_MASK (0x7ff<<OHCI_ED_MPS_SHIFT) 75f1ae32a1SGerd Hoffmann 76f1ae32a1SGerd Hoffmann /* Flags in the head field of an Endpoint Desciptor. */ 77f1ae32a1SGerd Hoffmann #define OHCI_ED_H 1 78f1ae32a1SGerd Hoffmann #define OHCI_ED_C 2 79f1ae32a1SGerd Hoffmann 80f1ae32a1SGerd Hoffmann /* Bitfields for the first word of a Transfer Desciptor. */ 81f1ae32a1SGerd Hoffmann #define OHCI_TD_R (1<<18) 82f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_SHIFT 19 83f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT) 84f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_SHIFT 21 85f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT) 86f1ae32a1SGerd Hoffmann #define OHCI_TD_T0 (1<<24) 87f1ae32a1SGerd Hoffmann #define OHCI_TD_T1 (1<<25) 88f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_SHIFT 26 89f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT) 90f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_SHIFT 28 91f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT) 92f1ae32a1SGerd Hoffmann 93f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Isochronous Transfer Desciptor. */ 94f1ae32a1SGerd Hoffmann /* CC & DI - same as in the General Transfer Desciptor */ 95f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_SHIFT 0 96f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT) 97f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_SHIFT 24 98f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT) 99f1ae32a1SGerd Hoffmann 100f1ae32a1SGerd Hoffmann /* Isochronous Transfer Desciptor - Offset / PacketStatusWord */ 101f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_SHIFT 12 102f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT) 103f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_SHIFT 0 104f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT) 105f1ae32a1SGerd Hoffmann 106f1ae32a1SGerd Hoffmann #define OHCI_PAGE_MASK 0xfffff000 107f1ae32a1SGerd Hoffmann #define OHCI_OFFSET_MASK 0xfff 108f1ae32a1SGerd Hoffmann 109f1ae32a1SGerd Hoffmann #define OHCI_DPTR_MASK 0xfffffff0 110f1ae32a1SGerd Hoffmann 111f1ae32a1SGerd Hoffmann #define OHCI_BM(val, field) \ 112f1ae32a1SGerd Hoffmann (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT) 113f1ae32a1SGerd Hoffmann 114f1ae32a1SGerd Hoffmann #define OHCI_SET_BM(val, field, newval) do { \ 115f1ae32a1SGerd Hoffmann val &= ~OHCI_##field##_MASK; \ 116f1ae32a1SGerd Hoffmann val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ 117f1ae32a1SGerd Hoffmann } while(0) 118f1ae32a1SGerd Hoffmann 119f1ae32a1SGerd Hoffmann /* endpoint descriptor */ 120f1ae32a1SGerd Hoffmann struct ohci_ed { 121f1ae32a1SGerd Hoffmann uint32_t flags; 122f1ae32a1SGerd Hoffmann uint32_t tail; 123f1ae32a1SGerd Hoffmann uint32_t head; 124f1ae32a1SGerd Hoffmann uint32_t next; 125f1ae32a1SGerd Hoffmann }; 126f1ae32a1SGerd Hoffmann 127f1ae32a1SGerd Hoffmann /* General transfer descriptor */ 128f1ae32a1SGerd Hoffmann struct ohci_td { 129f1ae32a1SGerd Hoffmann uint32_t flags; 130f1ae32a1SGerd Hoffmann uint32_t cbp; 131f1ae32a1SGerd Hoffmann uint32_t next; 132f1ae32a1SGerd Hoffmann uint32_t be; 133f1ae32a1SGerd Hoffmann }; 134f1ae32a1SGerd Hoffmann 135f1ae32a1SGerd Hoffmann /* Isochronous transfer descriptor */ 136f1ae32a1SGerd Hoffmann struct ohci_iso_td { 137f1ae32a1SGerd Hoffmann uint32_t flags; 138f1ae32a1SGerd Hoffmann uint32_t bp; 139f1ae32a1SGerd Hoffmann uint32_t next; 140f1ae32a1SGerd Hoffmann uint32_t be; 141f1ae32a1SGerd Hoffmann uint16_t offset[8]; 142f1ae32a1SGerd Hoffmann }; 143f1ae32a1SGerd Hoffmann 144f1ae32a1SGerd Hoffmann #define USB_HZ 12000000 145f1ae32a1SGerd Hoffmann 146f1ae32a1SGerd Hoffmann /* OHCI Local stuff */ 147f1ae32a1SGerd Hoffmann #define OHCI_CTL_CBSR ((1<<0)|(1<<1)) 148f1ae32a1SGerd Hoffmann #define OHCI_CTL_PLE (1<<2) 149f1ae32a1SGerd Hoffmann #define OHCI_CTL_IE (1<<3) 150f1ae32a1SGerd Hoffmann #define OHCI_CTL_CLE (1<<4) 151f1ae32a1SGerd Hoffmann #define OHCI_CTL_BLE (1<<5) 152f1ae32a1SGerd Hoffmann #define OHCI_CTL_HCFS ((1<<6)|(1<<7)) 153f1ae32a1SGerd Hoffmann #define OHCI_USB_RESET 0x00 154f1ae32a1SGerd Hoffmann #define OHCI_USB_RESUME 0x40 155f1ae32a1SGerd Hoffmann #define OHCI_USB_OPERATIONAL 0x80 156f1ae32a1SGerd Hoffmann #define OHCI_USB_SUSPEND 0xc0 157f1ae32a1SGerd Hoffmann #define OHCI_CTL_IR (1<<8) 158f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWC (1<<9) 159f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWE (1<<10) 160f1ae32a1SGerd Hoffmann 161f1ae32a1SGerd Hoffmann #define OHCI_STATUS_HCR (1<<0) 162f1ae32a1SGerd Hoffmann #define OHCI_STATUS_CLF (1<<1) 163f1ae32a1SGerd Hoffmann #define OHCI_STATUS_BLF (1<<2) 164f1ae32a1SGerd Hoffmann #define OHCI_STATUS_OCR (1<<3) 165f1ae32a1SGerd Hoffmann #define OHCI_STATUS_SOC ((1<<6)|(1<<7)) 166f1ae32a1SGerd Hoffmann 16700b01793SPeter Maydell #define OHCI_INTR_SO (1U<<0) /* Scheduling overrun */ 16800b01793SPeter Maydell #define OHCI_INTR_WD (1U<<1) /* HcDoneHead writeback */ 16900b01793SPeter Maydell #define OHCI_INTR_SF (1U<<2) /* Start of frame */ 17000b01793SPeter Maydell #define OHCI_INTR_RD (1U<<3) /* Resume detect */ 17100b01793SPeter Maydell #define OHCI_INTR_UE (1U<<4) /* Unrecoverable error */ 17200b01793SPeter Maydell #define OHCI_INTR_FNO (1U<<5) /* Frame number overflow */ 17300b01793SPeter Maydell #define OHCI_INTR_RHSC (1U<<6) /* Root hub status change */ 17400b01793SPeter Maydell #define OHCI_INTR_OC (1U<<30) /* Ownership change */ 17500b01793SPeter Maydell #define OHCI_INTR_MIE (1U<<31) /* Master Interrupt Enable */ 176f1ae32a1SGerd Hoffmann 177f1ae32a1SGerd Hoffmann #define OHCI_HCCA_SIZE 0x100 178f1ae32a1SGerd Hoffmann #define OHCI_HCCA_MASK 0xffffff00 179f1ae32a1SGerd Hoffmann 180f1ae32a1SGerd Hoffmann #define OHCI_EDPTR_MASK 0xfffffff0 181f1ae32a1SGerd Hoffmann 182f1ae32a1SGerd Hoffmann #define OHCI_FMI_FI 0x00003fff 183f1ae32a1SGerd Hoffmann #define OHCI_FMI_FSMPS 0xffff0000 184f1ae32a1SGerd Hoffmann #define OHCI_FMI_FIT 0x80000000 185f1ae32a1SGerd Hoffmann 18600b01793SPeter Maydell #define OHCI_FR_RT (1U<<31) 187f1ae32a1SGerd Hoffmann 188f1ae32a1SGerd Hoffmann #define OHCI_LS_THRESH 0x628 189f1ae32a1SGerd Hoffmann 190f1ae32a1SGerd Hoffmann #define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ 191f1ae32a1SGerd Hoffmann #define OHCI_RHA_PSM (1<<8) 192f1ae32a1SGerd Hoffmann #define OHCI_RHA_NPS (1<<9) 193f1ae32a1SGerd Hoffmann #define OHCI_RHA_DT (1<<10) 194f1ae32a1SGerd Hoffmann #define OHCI_RHA_OCPM (1<<11) 195f1ae32a1SGerd Hoffmann #define OHCI_RHA_NOCP (1<<12) 196f1ae32a1SGerd Hoffmann #define OHCI_RHA_POTPGT_MASK 0xff000000 197f1ae32a1SGerd Hoffmann 19800b01793SPeter Maydell #define OHCI_RHS_LPS (1U<<0) 19900b01793SPeter Maydell #define OHCI_RHS_OCI (1U<<1) 20000b01793SPeter Maydell #define OHCI_RHS_DRWE (1U<<15) 20100b01793SPeter Maydell #define OHCI_RHS_LPSC (1U<<16) 20200b01793SPeter Maydell #define OHCI_RHS_OCIC (1U<<17) 20300b01793SPeter Maydell #define OHCI_RHS_CRWE (1U<<31) 204f1ae32a1SGerd Hoffmann 205f1ae32a1SGerd Hoffmann #define OHCI_PORT_CCS (1<<0) 206f1ae32a1SGerd Hoffmann #define OHCI_PORT_PES (1<<1) 207f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSS (1<<2) 208f1ae32a1SGerd Hoffmann #define OHCI_PORT_POCI (1<<3) 209f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRS (1<<4) 210f1ae32a1SGerd Hoffmann #define OHCI_PORT_PPS (1<<8) 211f1ae32a1SGerd Hoffmann #define OHCI_PORT_LSDA (1<<9) 212f1ae32a1SGerd Hoffmann #define OHCI_PORT_CSC (1<<16) 213f1ae32a1SGerd Hoffmann #define OHCI_PORT_PESC (1<<17) 214f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSSC (1<<18) 215f1ae32a1SGerd Hoffmann #define OHCI_PORT_OCIC (1<<19) 216f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRSC (1<<20) 217f1ae32a1SGerd Hoffmann #define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ 218f1ae32a1SGerd Hoffmann |OHCI_PORT_OCIC|OHCI_PORT_PRSC) 219f1ae32a1SGerd Hoffmann 220f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_SETUP 0x0 221f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_OUT 0x1 222f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_IN 0x2 223f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_RESERVED 0x3 224f1ae32a1SGerd Hoffmann 225f1ae32a1SGerd Hoffmann #define OHCI_CC_NOERROR 0x0 226f1ae32a1SGerd Hoffmann #define OHCI_CC_CRC 0x1 227f1ae32a1SGerd Hoffmann #define OHCI_CC_BITSTUFFING 0x2 228f1ae32a1SGerd Hoffmann #define OHCI_CC_DATATOGGLEMISMATCH 0x3 229f1ae32a1SGerd Hoffmann #define OHCI_CC_STALL 0x4 230f1ae32a1SGerd Hoffmann #define OHCI_CC_DEVICENOTRESPONDING 0x5 231f1ae32a1SGerd Hoffmann #define OHCI_CC_PIDCHECKFAILURE 0x6 232f1ae32a1SGerd Hoffmann #define OHCI_CC_UNDEXPETEDPID 0x7 233f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAOVERRUN 0x8 234f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAUNDERRUN 0x9 235f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFEROVERRUN 0xc 236f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFERUNDERRUN 0xd 237f1ae32a1SGerd Hoffmann 238f1ae32a1SGerd Hoffmann #define OHCI_HRESET_FSBIR (1 << 0) 239f1ae32a1SGerd Hoffmann 24072e0c127SThomas Huth static void ohci_die(OHCIState *ohci) 24172e0c127SThomas Huth { 24272e0c127SThomas Huth ohci->ohci_die(ohci); 24372e0c127SThomas Huth } 244cf66ee8eSAlexey Kardashevskiy 245f1ae32a1SGerd Hoffmann /* Update IRQ levels */ 246f1ae32a1SGerd Hoffmann static inline void ohci_intr_update(OHCIState *ohci) 247f1ae32a1SGerd Hoffmann { 248f1ae32a1SGerd Hoffmann int level = 0; 249f1ae32a1SGerd Hoffmann 250f1ae32a1SGerd Hoffmann if ((ohci->intr & OHCI_INTR_MIE) && 251f1ae32a1SGerd Hoffmann (ohci->intr_status & ohci->intr)) 252f1ae32a1SGerd Hoffmann level = 1; 253f1ae32a1SGerd Hoffmann 254f1ae32a1SGerd Hoffmann qemu_set_irq(ohci->irq, level); 255f1ae32a1SGerd Hoffmann } 256f1ae32a1SGerd Hoffmann 257f1ae32a1SGerd Hoffmann /* Set an interrupt */ 258f1ae32a1SGerd Hoffmann static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) 259f1ae32a1SGerd Hoffmann { 260f1ae32a1SGerd Hoffmann ohci->intr_status |= intr; 261f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 262f1ae32a1SGerd Hoffmann } 263f1ae32a1SGerd Hoffmann 264f1ae32a1SGerd Hoffmann /* Attach or detach a device on a root hub port. */ 265f1ae32a1SGerd Hoffmann static void ohci_attach(USBPort *port1) 266f1ae32a1SGerd Hoffmann { 267f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 268f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 269f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 270f1ae32a1SGerd Hoffmann 271f1ae32a1SGerd Hoffmann /* set connect status */ 272f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; 273f1ae32a1SGerd Hoffmann 274f1ae32a1SGerd Hoffmann /* update speed */ 275f1ae32a1SGerd Hoffmann if (port->port.dev->speed == USB_SPEED_LOW) { 276f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_LSDA; 277f1ae32a1SGerd Hoffmann } else { 278f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_LSDA; 279f1ae32a1SGerd Hoffmann } 280f1ae32a1SGerd Hoffmann 281f1ae32a1SGerd Hoffmann /* notify of remote-wakeup */ 282f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 283f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RD); 284f1ae32a1SGerd Hoffmann } 285f1ae32a1SGerd Hoffmann 286dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_attach(port1->index); 287f1ae32a1SGerd Hoffmann 288f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 289f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 290f1ae32a1SGerd Hoffmann } 291f1ae32a1SGerd Hoffmann } 292f1ae32a1SGerd Hoffmann 293f1ae32a1SGerd Hoffmann static void ohci_detach(USBPort *port1) 294f1ae32a1SGerd Hoffmann { 295f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 296f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 297f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 298f1ae32a1SGerd Hoffmann 299f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, port1->dev); 300f1ae32a1SGerd Hoffmann 301f1ae32a1SGerd Hoffmann /* set connect status */ 302f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_CCS) { 303f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_CCS; 304f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CSC; 305f1ae32a1SGerd Hoffmann } 306f1ae32a1SGerd Hoffmann /* disable port */ 307f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PES) { 308f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 309f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PESC; 310f1ae32a1SGerd Hoffmann } 311dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_detach(port1->index); 312f1ae32a1SGerd Hoffmann 313f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 314f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 315f1ae32a1SGerd Hoffmann } 316f1ae32a1SGerd Hoffmann } 317f1ae32a1SGerd Hoffmann 318f1ae32a1SGerd Hoffmann static void ohci_wakeup(USBPort *port1) 319f1ae32a1SGerd Hoffmann { 320f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 321f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 322f1ae32a1SGerd Hoffmann uint32_t intr = 0; 323f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PSS) { 324dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_wakeup(port1->index); 325f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PSSC; 326f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PSS; 327f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RHSC; 328f1ae32a1SGerd Hoffmann } 329f1ae32a1SGerd Hoffmann /* Note that the controller can be suspended even if this port is not */ 330f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 331dc1f5988SAlexey Kardashevskiy trace_usb_ohci_remote_wakeup(s->name); 332f1ae32a1SGerd Hoffmann /* This is the one state transition the controller can do by itself */ 333f1ae32a1SGerd Hoffmann s->ctl &= ~OHCI_CTL_HCFS; 334f1ae32a1SGerd Hoffmann s->ctl |= OHCI_USB_RESUME; 335f1ae32a1SGerd Hoffmann /* In suspend mode only ResumeDetected is possible, not RHSC: 336f1ae32a1SGerd Hoffmann * see the OHCI spec 5.1.2.3. 337f1ae32a1SGerd Hoffmann */ 338f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RD; 339f1ae32a1SGerd Hoffmann } 340f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, intr); 341f1ae32a1SGerd Hoffmann } 342f1ae32a1SGerd Hoffmann 343f1ae32a1SGerd Hoffmann static void ohci_child_detach(USBPort *port1, USBDevice *child) 344f1ae32a1SGerd Hoffmann { 345f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 346f1ae32a1SGerd Hoffmann 347f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, child); 348f1ae32a1SGerd Hoffmann } 349f1ae32a1SGerd Hoffmann 350f1ae32a1SGerd Hoffmann static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr) 351f1ae32a1SGerd Hoffmann { 352f1ae32a1SGerd Hoffmann USBDevice *dev; 353f1ae32a1SGerd Hoffmann int i; 354f1ae32a1SGerd Hoffmann 355f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) { 356f1ae32a1SGerd Hoffmann if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) { 357f1ae32a1SGerd Hoffmann continue; 358f1ae32a1SGerd Hoffmann } 359f1ae32a1SGerd Hoffmann dev = usb_find_device(&ohci->rhport[i].port, addr); 360f1ae32a1SGerd Hoffmann if (dev != NULL) { 361f1ae32a1SGerd Hoffmann return dev; 362f1ae32a1SGerd Hoffmann } 363f1ae32a1SGerd Hoffmann } 364f1ae32a1SGerd Hoffmann return NULL; 365f1ae32a1SGerd Hoffmann } 366f1ae32a1SGerd Hoffmann 36734d97308SThomas Huth void ohci_stop_endpoints(OHCIState *ohci) 368f79738b0SHans de Goede { 369f79738b0SHans de Goede USBDevice *dev; 370f79738b0SHans de Goede int i, j; 371f79738b0SHans de Goede 372f79738b0SHans de Goede for (i = 0; i < ohci->num_ports; i++) { 373f79738b0SHans de Goede dev = ohci->rhport[i].port.dev; 374f79738b0SHans de Goede if (dev && dev->attached) { 375f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_ctl); 376f79738b0SHans de Goede for (j = 0; j < USB_MAX_ENDPOINTS; j++) { 377f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_in[j]); 378f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_out[j]); 379f79738b0SHans de Goede } 380f79738b0SHans de Goede } 381f79738b0SHans de Goede } 382f79738b0SHans de Goede } 383f79738b0SHans de Goede 38484d04e21SHervé Poussineau static void ohci_roothub_reset(OHCIState *ohci) 385f1ae32a1SGerd Hoffmann { 386f1ae32a1SGerd Hoffmann OHCIPort *port; 387f1ae32a1SGerd Hoffmann int i; 388f1ae32a1SGerd Hoffmann 389f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 39084d04e21SHervé Poussineau ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; 39184d04e21SHervé Poussineau ohci->rhdesc_b = 0x0; /* Impl. specific */ 39284d04e21SHervé Poussineau ohci->rhstatus = 0; 39384d04e21SHervé Poussineau 39484d04e21SHervé Poussineau for (i = 0; i < ohci->num_ports; i++) { 39584d04e21SHervé Poussineau port = &ohci->rhport[i]; 39684d04e21SHervé Poussineau port->ctrl = 0; 39784d04e21SHervé Poussineau if (port->port.dev && port->port.dev->attached) { 39884d04e21SHervé Poussineau usb_port_reset(&port->port); 39984d04e21SHervé Poussineau } 40084d04e21SHervé Poussineau } 40184d04e21SHervé Poussineau if (ohci->async_td) { 40284d04e21SHervé Poussineau usb_cancel_packet(&ohci->usb_packet); 40384d04e21SHervé Poussineau ohci->async_td = 0; 40484d04e21SHervé Poussineau } 40584d04e21SHervé Poussineau ohci_stop_endpoints(ohci); 40684d04e21SHervé Poussineau } 40784d04e21SHervé Poussineau 40884d04e21SHervé Poussineau /* Reset the controller */ 40984d04e21SHervé Poussineau static void ohci_soft_reset(OHCIState *ohci) 41084d04e21SHervé Poussineau { 41184d04e21SHervé Poussineau trace_usb_ohci_reset(ohci->name); 41284d04e21SHervé Poussineau 41384d04e21SHervé Poussineau ohci_bus_stop(ohci); 41484d04e21SHervé Poussineau ohci->ctl = (ohci->ctl & OHCI_CTL_IR) | OHCI_USB_SUSPEND; 415f1ae32a1SGerd Hoffmann ohci->old_ctl = 0; 416f1ae32a1SGerd Hoffmann ohci->status = 0; 417f1ae32a1SGerd Hoffmann ohci->intr_status = 0; 418f1ae32a1SGerd Hoffmann ohci->intr = OHCI_INTR_MIE; 419f1ae32a1SGerd Hoffmann 420f1ae32a1SGerd Hoffmann ohci->hcca = 0; 421f1ae32a1SGerd Hoffmann ohci->ctrl_head = ohci->ctrl_cur = 0; 422f1ae32a1SGerd Hoffmann ohci->bulk_head = ohci->bulk_cur = 0; 423f1ae32a1SGerd Hoffmann ohci->per_cur = 0; 424f1ae32a1SGerd Hoffmann ohci->done = 0; 425f1ae32a1SGerd Hoffmann ohci->done_count = 7; 426f1ae32a1SGerd Hoffmann 427f1ae32a1SGerd Hoffmann /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? 428f1ae32a1SGerd Hoffmann * I took the value linux sets ... 429f1ae32a1SGerd Hoffmann */ 430f1ae32a1SGerd Hoffmann ohci->fsmps = 0x2778; 431f1ae32a1SGerd Hoffmann ohci->fi = 0x2edf; 432f1ae32a1SGerd Hoffmann ohci->fit = 0; 433f1ae32a1SGerd Hoffmann ohci->frt = 0; 434f1ae32a1SGerd Hoffmann ohci->frame_number = 0; 435f1ae32a1SGerd Hoffmann ohci->pstart = 0; 436f1ae32a1SGerd Hoffmann ohci->lst = OHCI_LS_THRESH; 43784d04e21SHervé Poussineau } 438f1ae32a1SGerd Hoffmann 43934d97308SThomas Huth void ohci_hard_reset(OHCIState *ohci) 440f1ae32a1SGerd Hoffmann { 44184d04e21SHervé Poussineau ohci_soft_reset(ohci); 44284d04e21SHervé Poussineau ohci->ctl = 0; 44384d04e21SHervé Poussineau ohci_roothub_reset(ohci); 444f1ae32a1SGerd Hoffmann } 445f1ae32a1SGerd Hoffmann 446f1ae32a1SGerd Hoffmann /* Get an array of dwords from main memory */ 447f1ae32a1SGerd Hoffmann static inline int get_dwords(OHCIState *ohci, 4489ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 449f1ae32a1SGerd Hoffmann { 450f1ae32a1SGerd Hoffmann int i; 451f1ae32a1SGerd Hoffmann 452f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 453f1ae32a1SGerd Hoffmann 454f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 455*ba06fe8aSPhilippe Mathieu-Daudé if (dma_memory_read(ohci->as, addr, 456*ba06fe8aSPhilippe Mathieu-Daudé buf, sizeof(*buf), MEMTXATTRS_UNSPECIFIED)) { 457cf66ee8eSAlexey Kardashevskiy return -1; 458cf66ee8eSAlexey Kardashevskiy } 459f1ae32a1SGerd Hoffmann *buf = le32_to_cpu(*buf); 460f1ae32a1SGerd Hoffmann } 461f1ae32a1SGerd Hoffmann 462cf66ee8eSAlexey Kardashevskiy return 0; 463f1ae32a1SGerd Hoffmann } 464f1ae32a1SGerd Hoffmann 465f1ae32a1SGerd Hoffmann /* Put an array of dwords in to main memory */ 466f1ae32a1SGerd Hoffmann static inline int put_dwords(OHCIState *ohci, 4679ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 468f1ae32a1SGerd Hoffmann { 469f1ae32a1SGerd Hoffmann int i; 470f1ae32a1SGerd Hoffmann 471f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 472f1ae32a1SGerd Hoffmann 473f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 474f1ae32a1SGerd Hoffmann uint32_t tmp = cpu_to_le32(*buf); 475*ba06fe8aSPhilippe Mathieu-Daudé if (dma_memory_write(ohci->as, addr, 476*ba06fe8aSPhilippe Mathieu-Daudé &tmp, sizeof(tmp), MEMTXATTRS_UNSPECIFIED)) { 477cf66ee8eSAlexey Kardashevskiy return -1; 478cf66ee8eSAlexey Kardashevskiy } 479f1ae32a1SGerd Hoffmann } 480f1ae32a1SGerd Hoffmann 481cf66ee8eSAlexey Kardashevskiy return 0; 482f1ae32a1SGerd Hoffmann } 483f1ae32a1SGerd Hoffmann 484f1ae32a1SGerd Hoffmann /* Get an array of words from main memory */ 485f1ae32a1SGerd Hoffmann static inline int get_words(OHCIState *ohci, 4869ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 487f1ae32a1SGerd Hoffmann { 488f1ae32a1SGerd Hoffmann int i; 489f1ae32a1SGerd Hoffmann 490f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 491f1ae32a1SGerd Hoffmann 492f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 493*ba06fe8aSPhilippe Mathieu-Daudé if (dma_memory_read(ohci->as, addr, 494*ba06fe8aSPhilippe Mathieu-Daudé buf, sizeof(*buf), MEMTXATTRS_UNSPECIFIED)) { 495cf66ee8eSAlexey Kardashevskiy return -1; 496cf66ee8eSAlexey Kardashevskiy } 497f1ae32a1SGerd Hoffmann *buf = le16_to_cpu(*buf); 498f1ae32a1SGerd Hoffmann } 499f1ae32a1SGerd Hoffmann 500cf66ee8eSAlexey Kardashevskiy return 0; 501f1ae32a1SGerd Hoffmann } 502f1ae32a1SGerd Hoffmann 503f1ae32a1SGerd Hoffmann /* Put an array of words in to main memory */ 504f1ae32a1SGerd Hoffmann static inline int put_words(OHCIState *ohci, 5059ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 506f1ae32a1SGerd Hoffmann { 507f1ae32a1SGerd Hoffmann int i; 508f1ae32a1SGerd Hoffmann 509f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 510f1ae32a1SGerd Hoffmann 511f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 512f1ae32a1SGerd Hoffmann uint16_t tmp = cpu_to_le16(*buf); 513*ba06fe8aSPhilippe Mathieu-Daudé if (dma_memory_write(ohci->as, addr, 514*ba06fe8aSPhilippe Mathieu-Daudé &tmp, sizeof(tmp), MEMTXATTRS_UNSPECIFIED)) { 515cf66ee8eSAlexey Kardashevskiy return -1; 516cf66ee8eSAlexey Kardashevskiy } 517f1ae32a1SGerd Hoffmann } 518f1ae32a1SGerd Hoffmann 519cf66ee8eSAlexey Kardashevskiy return 0; 520f1ae32a1SGerd Hoffmann } 521f1ae32a1SGerd Hoffmann 522f1ae32a1SGerd Hoffmann static inline int ohci_read_ed(OHCIState *ohci, 5239ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 524f1ae32a1SGerd Hoffmann { 525f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2); 526f1ae32a1SGerd Hoffmann } 527f1ae32a1SGerd Hoffmann 528f1ae32a1SGerd Hoffmann static inline int ohci_read_td(OHCIState *ohci, 5299ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 530f1ae32a1SGerd Hoffmann { 531f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 532f1ae32a1SGerd Hoffmann } 533f1ae32a1SGerd Hoffmann 534f1ae32a1SGerd Hoffmann static inline int ohci_read_iso_td(OHCIState *ohci, 5359ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 536f1ae32a1SGerd Hoffmann { 537cf66ee8eSAlexey Kardashevskiy return get_dwords(ohci, addr, (uint32_t *)td, 4) || 538cf66ee8eSAlexey Kardashevskiy get_words(ohci, addr + 16, td->offset, 8); 539f1ae32a1SGerd Hoffmann } 540f1ae32a1SGerd Hoffmann 541f1ae32a1SGerd Hoffmann static inline int ohci_read_hcca(OHCIState *ohci, 5429ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 543f1ae32a1SGerd Hoffmann { 544*ba06fe8aSPhilippe Mathieu-Daudé return dma_memory_read(ohci->as, addr + ohci->localmem_base, hcca, 545*ba06fe8aSPhilippe Mathieu-Daudé sizeof(*hcca), MEMTXATTRS_UNSPECIFIED); 546f1ae32a1SGerd Hoffmann } 547f1ae32a1SGerd Hoffmann 548f1ae32a1SGerd Hoffmann static inline int ohci_put_ed(OHCIState *ohci, 5499ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 550f1ae32a1SGerd Hoffmann { 55186e18caeSWei Yang /* ed->tail is under control of the HCD. 55286e18caeSWei Yang * Since just ed->head is changed by HC, just write back this 55386e18caeSWei Yang */ 55486e18caeSWei Yang 55586e18caeSWei Yang return put_dwords(ohci, addr + ED_WBACK_OFFSET, 55686e18caeSWei Yang (uint32_t *)((char *)ed + ED_WBACK_OFFSET), 55786e18caeSWei Yang ED_WBACK_SIZE >> 2); 558f1ae32a1SGerd Hoffmann } 559f1ae32a1SGerd Hoffmann 560f1ae32a1SGerd Hoffmann static inline int ohci_put_td(OHCIState *ohci, 5619ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 562f1ae32a1SGerd Hoffmann { 563f1ae32a1SGerd Hoffmann return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 564f1ae32a1SGerd Hoffmann } 565f1ae32a1SGerd Hoffmann 566f1ae32a1SGerd Hoffmann static inline int ohci_put_iso_td(OHCIState *ohci, 5679ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 568f1ae32a1SGerd Hoffmann { 569cae7f29cSJack Un return put_dwords(ohci, addr, (uint32_t *)td, 4) || 570cae7f29cSJack Un put_words(ohci, addr + 16, td->offset, 8); 571f1ae32a1SGerd Hoffmann } 572f1ae32a1SGerd Hoffmann 573f1ae32a1SGerd Hoffmann static inline int ohci_put_hcca(OHCIState *ohci, 5749ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 575f1ae32a1SGerd Hoffmann { 576cf66ee8eSAlexey Kardashevskiy return dma_memory_write(ohci->as, 5779ac6a217SDavid Gibson addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, 57886e18caeSWei Yang (char *)hcca + HCCA_WRITEBACK_OFFSET, 579*ba06fe8aSPhilippe Mathieu-Daudé HCCA_WRITEBACK_SIZE, MEMTXATTRS_UNSPECIFIED); 580f1ae32a1SGerd Hoffmann } 581f1ae32a1SGerd Hoffmann 582f1ae32a1SGerd Hoffmann /* Read/Write the contents of a TD from/to main memory. */ 583cf66ee8eSAlexey Kardashevskiy static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, 5849ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 585f1ae32a1SGerd Hoffmann { 5869ac6a217SDavid Gibson dma_addr_t ptr, n; 587f1ae32a1SGerd Hoffmann 588f1ae32a1SGerd Hoffmann ptr = td->cbp; 589f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 590f1ae32a1SGerd Hoffmann if (n > len) 591f1ae32a1SGerd Hoffmann n = len; 592cf66ee8eSAlexey Kardashevskiy 59323faf569SPhilippe Mathieu-Daudé if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 59423faf569SPhilippe Mathieu-Daudé n, dir, MEMTXATTRS_UNSPECIFIED)) { 595cf66ee8eSAlexey Kardashevskiy return -1; 596cf66ee8eSAlexey Kardashevskiy } 597cf66ee8eSAlexey Kardashevskiy if (n == len) { 598cf66ee8eSAlexey Kardashevskiy return 0; 599cf66ee8eSAlexey Kardashevskiy } 600f1ae32a1SGerd Hoffmann ptr = td->be & ~0xfffu; 601f1ae32a1SGerd Hoffmann buf += n; 602cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 60323faf569SPhilippe Mathieu-Daudé len - n, dir, MEMTXATTRS_UNSPECIFIED)) { 604cf66ee8eSAlexey Kardashevskiy return -1; 605cf66ee8eSAlexey Kardashevskiy } 606cf66ee8eSAlexey Kardashevskiy return 0; 607f1ae32a1SGerd Hoffmann } 608f1ae32a1SGerd Hoffmann 609f1ae32a1SGerd Hoffmann /* Read/Write the contents of an ISO TD from/to main memory. */ 610cf66ee8eSAlexey Kardashevskiy static int ohci_copy_iso_td(OHCIState *ohci, 611f1ae32a1SGerd Hoffmann uint32_t start_addr, uint32_t end_addr, 6129ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 613f1ae32a1SGerd Hoffmann { 6149ac6a217SDavid Gibson dma_addr_t ptr, n; 615f1ae32a1SGerd Hoffmann 616f1ae32a1SGerd Hoffmann ptr = start_addr; 617f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 618f1ae32a1SGerd Hoffmann if (n > len) 619f1ae32a1SGerd Hoffmann n = len; 620cf66ee8eSAlexey Kardashevskiy 62123faf569SPhilippe Mathieu-Daudé if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 62223faf569SPhilippe Mathieu-Daudé n, dir, MEMTXATTRS_UNSPECIFIED)) { 623cf66ee8eSAlexey Kardashevskiy return -1; 624cf66ee8eSAlexey Kardashevskiy } 625cf66ee8eSAlexey Kardashevskiy if (n == len) { 626cf66ee8eSAlexey Kardashevskiy return 0; 627cf66ee8eSAlexey Kardashevskiy } 628f1ae32a1SGerd Hoffmann ptr = end_addr & ~0xfffu; 629f1ae32a1SGerd Hoffmann buf += n; 630cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 63123faf569SPhilippe Mathieu-Daudé len - n, dir, MEMTXATTRS_UNSPECIFIED)) { 632cf66ee8eSAlexey Kardashevskiy return -1; 633cf66ee8eSAlexey Kardashevskiy } 634cf66ee8eSAlexey Kardashevskiy return 0; 635f1ae32a1SGerd Hoffmann } 636f1ae32a1SGerd Hoffmann 637f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion); 638f1ae32a1SGerd Hoffmann 639f1ae32a1SGerd Hoffmann static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) 640f1ae32a1SGerd Hoffmann { 641f1ae32a1SGerd Hoffmann OHCIState *ohci = container_of(packet, OHCIState, usb_packet); 642dc1f5988SAlexey Kardashevskiy 643dc1f5988SAlexey Kardashevskiy trace_usb_ohci_async_complete(); 64469e25d26SAlexey Kardashevskiy ohci->async_complete = true; 645f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 1); 646f1ae32a1SGerd Hoffmann } 647f1ae32a1SGerd Hoffmann 648f1ae32a1SGerd Hoffmann #define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b))) 649f1ae32a1SGerd Hoffmann 650f1ae32a1SGerd Hoffmann static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, 651f1ae32a1SGerd Hoffmann int completion) 652f1ae32a1SGerd Hoffmann { 653f1ae32a1SGerd Hoffmann int dir; 654f1ae32a1SGerd Hoffmann size_t len = 0; 655f1ae32a1SGerd Hoffmann const char *str = NULL; 656f1ae32a1SGerd Hoffmann int pid; 657f1ae32a1SGerd Hoffmann int ret; 658f1ae32a1SGerd Hoffmann int i; 659f1ae32a1SGerd Hoffmann USBDevice *dev; 660f1ae32a1SGerd Hoffmann USBEndpoint *ep; 661f1ae32a1SGerd Hoffmann struct ohci_iso_td iso_td; 662f1ae32a1SGerd Hoffmann uint32_t addr; 663f1ae32a1SGerd Hoffmann uint16_t starting_frame; 664f1ae32a1SGerd Hoffmann int16_t relative_frame_number; 665f1ae32a1SGerd Hoffmann int frame_count; 666f1ae32a1SGerd Hoffmann uint32_t start_offset, next_offset, end_offset = 0; 667f1ae32a1SGerd Hoffmann uint32_t start_addr, end_addr; 668f1ae32a1SGerd Hoffmann 669f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 670f1ae32a1SGerd Hoffmann 671cf66ee8eSAlexey Kardashevskiy if (ohci_read_iso_td(ohci, addr, &iso_td)) { 672dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_read_failed(addr); 673cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 67426f670a2SLi Qiang return 1; 675f1ae32a1SGerd Hoffmann } 676f1ae32a1SGerd Hoffmann 677f1ae32a1SGerd Hoffmann starting_frame = OHCI_BM(iso_td.flags, TD_SF); 678f1ae32a1SGerd Hoffmann frame_count = OHCI_BM(iso_td.flags, TD_FC); 679f1ae32a1SGerd Hoffmann relative_frame_number = USUB(ohci->frame_number, starting_frame); 680f1ae32a1SGerd Hoffmann 681dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_head( 682f1ae32a1SGerd Hoffmann ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK, 683f1ae32a1SGerd Hoffmann iso_td.flags, iso_td.bp, iso_td.next, iso_td.be, 684f1ae32a1SGerd Hoffmann ohci->frame_number, starting_frame, 685bc0d104cSAlex Bennée frame_count, relative_frame_number); 6863af8f177SAlexey Kardashevskiy trace_usb_ohci_iso_td_head_offset( 6873af8f177SAlexey Kardashevskiy iso_td.offset[0], iso_td.offset[1], 6883af8f177SAlexey Kardashevskiy iso_td.offset[2], iso_td.offset[3], 6893af8f177SAlexey Kardashevskiy iso_td.offset[4], iso_td.offset[5], 6903af8f177SAlexey Kardashevskiy iso_td.offset[6], iso_td.offset[7]); 691f1ae32a1SGerd Hoffmann 692f1ae32a1SGerd Hoffmann if (relative_frame_number < 0) { 693dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number); 694f1ae32a1SGerd Hoffmann return 1; 695f1ae32a1SGerd Hoffmann } else if (relative_frame_number > frame_count) { 696f1ae32a1SGerd Hoffmann /* ISO TD expired - retire the TD to the Done Queue and continue with 697f1ae32a1SGerd Hoffmann the next ISO TD of the same ED */ 698dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number, 699f1ae32a1SGerd Hoffmann frame_count); 7001be90ebeSPrasad J Pandit if (OHCI_CC_DATAOVERRUN == OHCI_BM(iso_td.flags, TD_CC)) { 7011be90ebeSPrasad J Pandit /* avoid infinite loop */ 7021be90ebeSPrasad J Pandit return 1; 7031be90ebeSPrasad J Pandit } 704f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 705f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 706f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 707f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 708f1ae32a1SGerd Hoffmann ohci->done = addr; 709f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 710f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 711f1ae32a1SGerd Hoffmann ohci->done_count = i; 712cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 713cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 714cf66ee8eSAlexey Kardashevskiy return 1; 715cf66ee8eSAlexey Kardashevskiy } 716f1ae32a1SGerd Hoffmann return 0; 717f1ae32a1SGerd Hoffmann } 718f1ae32a1SGerd Hoffmann 719f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 720f1ae32a1SGerd Hoffmann switch (dir) { 721f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 722f1ae32a1SGerd Hoffmann str = "in"; 723f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 724f1ae32a1SGerd Hoffmann break; 725f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 726f1ae32a1SGerd Hoffmann str = "out"; 727f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 728f1ae32a1SGerd Hoffmann break; 729f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 730f1ae32a1SGerd Hoffmann str = "setup"; 731f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 732f1ae32a1SGerd Hoffmann break; 733f1ae32a1SGerd Hoffmann default: 734dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_direction(dir); 735f1ae32a1SGerd Hoffmann return 1; 736f1ae32a1SGerd Hoffmann } 737f1ae32a1SGerd Hoffmann 738f1ae32a1SGerd Hoffmann if (!iso_td.bp || !iso_td.be) { 739dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be); 740f1ae32a1SGerd Hoffmann return 1; 741f1ae32a1SGerd Hoffmann } 742f1ae32a1SGerd Hoffmann 743f1ae32a1SGerd Hoffmann start_offset = iso_td.offset[relative_frame_number]; 7441328fe0cSPrasad J Pandit if (relative_frame_number < frame_count) { 745f1ae32a1SGerd Hoffmann next_offset = iso_td.offset[relative_frame_number + 1]; 7461328fe0cSPrasad J Pandit } else { 7471328fe0cSPrasad J Pandit next_offset = iso_td.be; 7481328fe0cSPrasad J Pandit } 749f1ae32a1SGerd Hoffmann 750f1ae32a1SGerd Hoffmann if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 751f1ae32a1SGerd Hoffmann ((relative_frame_number < frame_count) && 752f1ae32a1SGerd Hoffmann !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) { 753dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset); 754f1ae32a1SGerd Hoffmann return 1; 755f1ae32a1SGerd Hoffmann } 756f1ae32a1SGerd Hoffmann 757f1ae32a1SGerd Hoffmann if ((relative_frame_number < frame_count) && (start_offset > next_offset)) { 758dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset); 759f1ae32a1SGerd Hoffmann return 1; 760f1ae32a1SGerd Hoffmann } 761f1ae32a1SGerd Hoffmann 762f1ae32a1SGerd Hoffmann if ((start_offset & 0x1000) == 0) { 763f1ae32a1SGerd Hoffmann start_addr = (iso_td.bp & OHCI_PAGE_MASK) | 764f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 765f1ae32a1SGerd Hoffmann } else { 766f1ae32a1SGerd Hoffmann start_addr = (iso_td.be & OHCI_PAGE_MASK) | 767f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 768f1ae32a1SGerd Hoffmann } 769f1ae32a1SGerd Hoffmann 770f1ae32a1SGerd Hoffmann if (relative_frame_number < frame_count) { 771f1ae32a1SGerd Hoffmann end_offset = next_offset - 1; 772f1ae32a1SGerd Hoffmann if ((end_offset & 0x1000) == 0) { 773f1ae32a1SGerd Hoffmann end_addr = (iso_td.bp & OHCI_PAGE_MASK) | 774f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 775f1ae32a1SGerd Hoffmann } else { 776f1ae32a1SGerd Hoffmann end_addr = (iso_td.be & OHCI_PAGE_MASK) | 777f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 778f1ae32a1SGerd Hoffmann } 779f1ae32a1SGerd Hoffmann } else { 780f1ae32a1SGerd Hoffmann /* Last packet in the ISO TD */ 7811328fe0cSPrasad J Pandit end_addr = next_offset; 7821328fe0cSPrasad J Pandit } 7831328fe0cSPrasad J Pandit 7841328fe0cSPrasad J Pandit if (start_addr > end_addr) { 7851328fe0cSPrasad J Pandit trace_usb_ohci_iso_td_bad_cc_overrun(start_addr, end_addr); 7861328fe0cSPrasad J Pandit return 1; 787f1ae32a1SGerd Hoffmann } 788f1ae32a1SGerd Hoffmann 789f1ae32a1SGerd Hoffmann if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { 790f1ae32a1SGerd Hoffmann len = (end_addr & OHCI_OFFSET_MASK) + 0x1001 791f1ae32a1SGerd Hoffmann - (start_addr & OHCI_OFFSET_MASK); 792f1ae32a1SGerd Hoffmann } else { 793f1ae32a1SGerd Hoffmann len = end_addr - start_addr + 1; 794f1ae32a1SGerd Hoffmann } 7951328fe0cSPrasad J Pandit if (len > sizeof(ohci->usb_buf)) { 7961328fe0cSPrasad J Pandit len = sizeof(ohci->usb_buf); 7971328fe0cSPrasad J Pandit } 798f1ae32a1SGerd Hoffmann 799f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 800cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 801cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 802cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 803cf66ee8eSAlexey Kardashevskiy return 1; 804cf66ee8eSAlexey Kardashevskiy } 805f1ae32a1SGerd Hoffmann } 806f1ae32a1SGerd Hoffmann 8079a77a0f5SHans de Goede if (!completion) { 808a6fb2ddbSHans de Goede bool int_req = relative_frame_number == frame_count && 809a6fb2ddbSHans de Goede OHCI_BM(iso_td.flags, TD_DI) == 0; 810f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 81142340fc3SLiam Merwick if (dev == NULL) { 81242340fc3SLiam Merwick trace_usb_ohci_td_dev_error(); 81342340fc3SLiam Merwick return 1; 81442340fc3SLiam Merwick } 815f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 8168550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req); 817f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); 8189a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 8199a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 82036dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 821f1ae32a1SGerd Hoffmann return 1; 822f1ae32a1SGerd Hoffmann } 823f1ae32a1SGerd Hoffmann } 8249a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 8259a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 8269a77a0f5SHans de Goede } else { 8279a77a0f5SHans de Goede ret = ohci->usb_packet.status; 8289a77a0f5SHans de Goede } 829f1ae32a1SGerd Hoffmann 830dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr, 831dc1f5988SAlexey Kardashevskiy str, len, ret); 832f1ae32a1SGerd Hoffmann 833f1ae32a1SGerd Hoffmann /* Writeback */ 834f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) { 835f1ae32a1SGerd Hoffmann /* IN transfer succeeded */ 836cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 837cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 838cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 839cf66ee8eSAlexey Kardashevskiy return 1; 840cf66ee8eSAlexey Kardashevskiy } 841f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 842f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 843f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret); 844f1ae32a1SGerd Hoffmann } else if (dir == OHCI_TD_DIR_OUT && ret == len) { 845f1ae32a1SGerd Hoffmann /* OUT transfer succeeded */ 846f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 847f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 848f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); 849f1ae32a1SGerd Hoffmann } else { 850f1ae32a1SGerd Hoffmann if (ret > (ssize_t) len) { 851dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_overrun(ret, len); 852f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 853f1ae32a1SGerd Hoffmann OHCI_CC_DATAOVERRUN); 854f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 855f1ae32a1SGerd Hoffmann len); 856f1ae32a1SGerd Hoffmann } else if (ret >= 0) { 857dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_underrun(ret); 858f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 859f1ae32a1SGerd Hoffmann OHCI_CC_DATAUNDERRUN); 860f1ae32a1SGerd Hoffmann } else { 861f1ae32a1SGerd Hoffmann switch (ret) { 862f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 863f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 864f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 865f1ae32a1SGerd Hoffmann OHCI_CC_DEVICENOTRESPONDING); 866f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 867f1ae32a1SGerd Hoffmann 0); 868f1ae32a1SGerd Hoffmann break; 869f1ae32a1SGerd Hoffmann case USB_RET_NAK: 870f1ae32a1SGerd Hoffmann case USB_RET_STALL: 871dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_nak(ret); 872f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 873f1ae32a1SGerd Hoffmann OHCI_CC_STALL); 874f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 875f1ae32a1SGerd Hoffmann 0); 876f1ae32a1SGerd Hoffmann break; 877f1ae32a1SGerd Hoffmann default: 878dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_response(ret); 879f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 880f1ae32a1SGerd Hoffmann OHCI_CC_UNDEXPETEDPID); 881f1ae32a1SGerd Hoffmann break; 882f1ae32a1SGerd Hoffmann } 883f1ae32a1SGerd Hoffmann } 884f1ae32a1SGerd Hoffmann } 885f1ae32a1SGerd Hoffmann 886f1ae32a1SGerd Hoffmann if (relative_frame_number == frame_count) { 887f1ae32a1SGerd Hoffmann /* Last data packet of ISO TD - retire the TD to the Done Queue */ 888f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR); 889f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 890f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 891f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 892f1ae32a1SGerd Hoffmann ohci->done = addr; 893f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 894f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 895f1ae32a1SGerd Hoffmann ohci->done_count = i; 896f1ae32a1SGerd Hoffmann } 897cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 898cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 899cf66ee8eSAlexey Kardashevskiy } 900f1ae32a1SGerd Hoffmann return 1; 901f1ae32a1SGerd Hoffmann } 902f1ae32a1SGerd Hoffmann 903dc1f5988SAlexey Kardashevskiy static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) 904dc1f5988SAlexey Kardashevskiy { 905d87aa138SStefan Hajnoczi bool print16; 906d87aa138SStefan Hajnoczi bool printall; 907dc1f5988SAlexey Kardashevskiy const int width = 16; 908dc1f5988SAlexey Kardashevskiy int i; 909dc1f5988SAlexey Kardashevskiy char tmp[3 * width + 1]; 910dc1f5988SAlexey Kardashevskiy char *p = tmp; 911dc1f5988SAlexey Kardashevskiy 912d87aa138SStefan Hajnoczi print16 = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_SHORT); 913d87aa138SStefan Hajnoczi printall = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_FULL); 914d87aa138SStefan Hajnoczi 915dc1f5988SAlexey Kardashevskiy if (!printall && !print16) { 916dc1f5988SAlexey Kardashevskiy return; 917dc1f5988SAlexey Kardashevskiy } 918dc1f5988SAlexey Kardashevskiy 919dc1f5988SAlexey Kardashevskiy for (i = 0; ; i++) { 920dc1f5988SAlexey Kardashevskiy if (i && (!(i % width) || (i == len))) { 921dc1f5988SAlexey Kardashevskiy if (!printall) { 922dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_short(msg, tmp); 923dc1f5988SAlexey Kardashevskiy break; 924dc1f5988SAlexey Kardashevskiy } 925dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_full(msg, tmp); 926dc1f5988SAlexey Kardashevskiy p = tmp; 927dc1f5988SAlexey Kardashevskiy *p = 0; 928dc1f5988SAlexey Kardashevskiy } 929dc1f5988SAlexey Kardashevskiy if (i == len) { 930dc1f5988SAlexey Kardashevskiy break; 931dc1f5988SAlexey Kardashevskiy } 932dc1f5988SAlexey Kardashevskiy 933dc1f5988SAlexey Kardashevskiy p += sprintf(p, " %.2x", buf[i]); 934dc1f5988SAlexey Kardashevskiy } 935dc1f5988SAlexey Kardashevskiy } 936dc1f5988SAlexey Kardashevskiy 937f1ae32a1SGerd Hoffmann /* Service a transport descriptor. 938f1ae32a1SGerd Hoffmann Returns nonzero to terminate processing of this endpoint. */ 939f1ae32a1SGerd Hoffmann 940f1ae32a1SGerd Hoffmann static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) 941f1ae32a1SGerd Hoffmann { 942f1ae32a1SGerd Hoffmann int dir; 943f1ae32a1SGerd Hoffmann size_t len = 0, pktlen = 0; 944f1ae32a1SGerd Hoffmann const char *str = NULL; 945f1ae32a1SGerd Hoffmann int pid; 946f1ae32a1SGerd Hoffmann int ret; 947f1ae32a1SGerd Hoffmann int i; 948f1ae32a1SGerd Hoffmann USBDevice *dev; 949f1ae32a1SGerd Hoffmann USBEndpoint *ep; 950f1ae32a1SGerd Hoffmann struct ohci_td td; 951f1ae32a1SGerd Hoffmann uint32_t addr; 952f1ae32a1SGerd Hoffmann int flag_r; 953f1ae32a1SGerd Hoffmann int completion; 954f1ae32a1SGerd Hoffmann 955f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 956f1ae32a1SGerd Hoffmann /* See if this TD has already been submitted to the device. */ 957f1ae32a1SGerd Hoffmann completion = (addr == ohci->async_td); 958f1ae32a1SGerd Hoffmann if (completion && !ohci->async_complete) { 959dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_skip_async(); 960f1ae32a1SGerd Hoffmann return 1; 961f1ae32a1SGerd Hoffmann } 962cf66ee8eSAlexey Kardashevskiy if (ohci_read_td(ohci, addr, &td)) { 963dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_read_error(addr); 964cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 9656ebc069dSLi Qiang return 1; 966f1ae32a1SGerd Hoffmann } 967f1ae32a1SGerd Hoffmann 968f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 969f1ae32a1SGerd Hoffmann switch (dir) { 970f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 971f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 972f1ae32a1SGerd Hoffmann /* Same value. */ 973f1ae32a1SGerd Hoffmann break; 974f1ae32a1SGerd Hoffmann default: 975f1ae32a1SGerd Hoffmann dir = OHCI_BM(td.flags, TD_DP); 976f1ae32a1SGerd Hoffmann break; 977f1ae32a1SGerd Hoffmann } 978f1ae32a1SGerd Hoffmann 979f1ae32a1SGerd Hoffmann switch (dir) { 980f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 981f1ae32a1SGerd Hoffmann str = "in"; 982f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 983f1ae32a1SGerd Hoffmann break; 984f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 985f1ae32a1SGerd Hoffmann str = "out"; 986f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 987f1ae32a1SGerd Hoffmann break; 988f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 989f1ae32a1SGerd Hoffmann str = "setup"; 990f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 991f1ae32a1SGerd Hoffmann break; 992f1ae32a1SGerd Hoffmann default: 993dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_direction(dir); 994f1ae32a1SGerd Hoffmann return 1; 995f1ae32a1SGerd Hoffmann } 996f1ae32a1SGerd Hoffmann if (td.cbp && td.be) { 997f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { 998f1ae32a1SGerd Hoffmann len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); 999f1ae32a1SGerd Hoffmann } else { 10001328fe0cSPrasad J Pandit if (td.cbp > td.be) { 10011328fe0cSPrasad J Pandit trace_usb_ohci_iso_td_bad_cc_overrun(td.cbp, td.be); 10021328fe0cSPrasad J Pandit ohci_die(ohci); 10031328fe0cSPrasad J Pandit return 1; 10041328fe0cSPrasad J Pandit } 1005f1ae32a1SGerd Hoffmann len = (td.be - td.cbp) + 1; 1006f1ae32a1SGerd Hoffmann } 10071328fe0cSPrasad J Pandit if (len > sizeof(ohci->usb_buf)) { 10081328fe0cSPrasad J Pandit len = sizeof(ohci->usb_buf); 10091328fe0cSPrasad J Pandit } 1010f1ae32a1SGerd Hoffmann 1011f1ae32a1SGerd Hoffmann pktlen = len; 1012f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 1013f1ae32a1SGerd Hoffmann /* The endpoint may not allow us to transfer it all now */ 1014f1ae32a1SGerd Hoffmann pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT; 1015f1ae32a1SGerd Hoffmann if (pktlen > len) { 1016f1ae32a1SGerd Hoffmann pktlen = len; 1017f1ae32a1SGerd Hoffmann } 1018f1ae32a1SGerd Hoffmann if (!completion) { 1019cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 1020cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 1021cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1022cf66ee8eSAlexey Kardashevskiy } 1023f1ae32a1SGerd Hoffmann } 1024f1ae32a1SGerd Hoffmann } 1025f1ae32a1SGerd Hoffmann } 1026f1ae32a1SGerd Hoffmann 1027f1ae32a1SGerd Hoffmann flag_r = (td.flags & OHCI_TD_R) != 0; 1028dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str, 1029dc1f5988SAlexey Kardashevskiy flag_r, td.cbp, td.be); 1030dc1f5988SAlexey Kardashevskiy ohci_td_pkt("OUT", ohci->usb_buf, pktlen); 1031f1ae32a1SGerd Hoffmann 1032f1ae32a1SGerd Hoffmann if (completion) { 1033f1ae32a1SGerd Hoffmann ohci->async_td = 0; 103469e25d26SAlexey Kardashevskiy ohci->async_complete = false; 1035f1ae32a1SGerd Hoffmann } else { 1036f1ae32a1SGerd Hoffmann if (ohci->async_td) { 1037f1ae32a1SGerd Hoffmann /* ??? The hardware should allow one active packet per 1038f1ae32a1SGerd Hoffmann endpoint. We only allow one active packet per controller. 1039f1ae32a1SGerd Hoffmann This should be sufficient as long as devices respond in a 1040f1ae32a1SGerd Hoffmann timely manner. 1041f1ae32a1SGerd Hoffmann */ 1042dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_too_many_pending(); 1043f1ae32a1SGerd Hoffmann return 1; 1044f1ae32a1SGerd Hoffmann } 1045f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 104642340fc3SLiam Merwick if (dev == NULL) { 104742340fc3SLiam Merwick trace_usb_ohci_td_dev_error(); 104842340fc3SLiam Merwick return 1; 104942340fc3SLiam Merwick } 1050f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 10518550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r, 1052a6fb2ddbSHans de Goede OHCI_BM(td.flags, TD_DI) == 0); 1053f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); 10549a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 1055dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_packet_status(ohci->usb_packet.status); 1056dc1f5988SAlexey Kardashevskiy 10579a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 105836dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 1059f1ae32a1SGerd Hoffmann ohci->async_td = addr; 1060f1ae32a1SGerd Hoffmann return 1; 1061f1ae32a1SGerd Hoffmann } 1062f1ae32a1SGerd Hoffmann } 10639a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 10649a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 10659a77a0f5SHans de Goede } else { 10669a77a0f5SHans de Goede ret = ohci->usb_packet.status; 10679a77a0f5SHans de Goede } 10689a77a0f5SHans de Goede 1069f1ae32a1SGerd Hoffmann if (ret >= 0) { 1070f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN) { 1071cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1072cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 1073cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1074cf66ee8eSAlexey Kardashevskiy } 1075dc1f5988SAlexey Kardashevskiy ohci_td_pkt("IN", ohci->usb_buf, pktlen); 1076f1ae32a1SGerd Hoffmann } else { 1077f1ae32a1SGerd Hoffmann ret = pktlen; 1078f1ae32a1SGerd Hoffmann } 1079f1ae32a1SGerd Hoffmann } 1080f1ae32a1SGerd Hoffmann 1081f1ae32a1SGerd Hoffmann /* Writeback */ 1082f1ae32a1SGerd Hoffmann if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { 1083f1ae32a1SGerd Hoffmann /* Transmission succeeded. */ 1084f1ae32a1SGerd Hoffmann if (ret == len) { 1085f1ae32a1SGerd Hoffmann td.cbp = 0; 1086f1ae32a1SGerd Hoffmann } else { 1087f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfff) + ret > 0xfff) { 1088f1ae32a1SGerd Hoffmann td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff); 1089f1ae32a1SGerd Hoffmann } else { 1090f1ae32a1SGerd Hoffmann td.cbp += ret; 1091f1ae32a1SGerd Hoffmann } 1092f1ae32a1SGerd Hoffmann } 1093f1ae32a1SGerd Hoffmann td.flags |= OHCI_TD_T1; 1094f1ae32a1SGerd Hoffmann td.flags ^= OHCI_TD_T0; 1095f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); 1096f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 0); 1097f1ae32a1SGerd Hoffmann 1098f1ae32a1SGerd Hoffmann if ((dir != OHCI_TD_DIR_IN) && (ret != len)) { 1099f1ae32a1SGerd Hoffmann /* Partial packet transfer: TD not ready to retire yet */ 1100f1ae32a1SGerd Hoffmann goto exit_no_retire; 1101f1ae32a1SGerd Hoffmann } 1102f1ae32a1SGerd Hoffmann 1103f1ae32a1SGerd Hoffmann /* Setting ED_C is part of the TD retirement process */ 1104f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_ED_C; 1105f1ae32a1SGerd Hoffmann if (td.flags & OHCI_TD_T0) 1106f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_C; 1107f1ae32a1SGerd Hoffmann } else { 1108f1ae32a1SGerd Hoffmann if (ret >= 0) { 1109dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_underrun(); 1110f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); 1111f1ae32a1SGerd Hoffmann } else { 1112f1ae32a1SGerd Hoffmann switch (ret) { 1113f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 1114f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 1115dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_dev_error(); 1116f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); 11174b351a0fSJán Veselý break; 1118f1ae32a1SGerd Hoffmann case USB_RET_NAK: 1119dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_nak(); 1120f1ae32a1SGerd Hoffmann return 1; 1121f1ae32a1SGerd Hoffmann case USB_RET_STALL: 1122dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_stall(); 1123f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); 1124f1ae32a1SGerd Hoffmann break; 1125f1ae32a1SGerd Hoffmann case USB_RET_BABBLE: 1126dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_babble(); 1127f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 1128f1ae32a1SGerd Hoffmann break; 1129f1ae32a1SGerd Hoffmann default: 1130dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_device_response(ret); 1131f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); 1132f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 3); 1133f1ae32a1SGerd Hoffmann break; 1134f1ae32a1SGerd Hoffmann } 1135cba42d61SMichael Tokarev /* An error occurred so we have to clear the interrupt counter. See 11367c48b95dSSebastian Bauer * spec at 6.4.4 on page 104 */ 11377c48b95dSSebastian Bauer ohci->done_count = 0; 1138f1ae32a1SGerd Hoffmann } 1139f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_H; 1140f1ae32a1SGerd Hoffmann } 1141f1ae32a1SGerd Hoffmann 1142f1ae32a1SGerd Hoffmann /* Retire this TD */ 1143f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 1144f1ae32a1SGerd Hoffmann ed->head |= td.next & OHCI_DPTR_MASK; 1145f1ae32a1SGerd Hoffmann td.next = ohci->done; 1146f1ae32a1SGerd Hoffmann ohci->done = addr; 1147f1ae32a1SGerd Hoffmann i = OHCI_BM(td.flags, TD_DI); 1148f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 1149f1ae32a1SGerd Hoffmann ohci->done_count = i; 1150f1ae32a1SGerd Hoffmann exit_no_retire: 1151cf66ee8eSAlexey Kardashevskiy if (ohci_put_td(ohci, addr, &td)) { 1152cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1153cf66ee8eSAlexey Kardashevskiy return 1; 1154cf66ee8eSAlexey Kardashevskiy } 1155f1ae32a1SGerd Hoffmann return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; 1156f1ae32a1SGerd Hoffmann } 1157f1ae32a1SGerd Hoffmann 1158f1ae32a1SGerd Hoffmann /* Service an endpoint list. Returns nonzero if active TD were found. */ 1159f1ae32a1SGerd Hoffmann static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) 1160f1ae32a1SGerd Hoffmann { 1161f1ae32a1SGerd Hoffmann struct ohci_ed ed; 1162f1ae32a1SGerd Hoffmann uint32_t next_ed; 1163f1ae32a1SGerd Hoffmann uint32_t cur; 1164f1ae32a1SGerd Hoffmann int active; 116595ed5693SLi Qiang uint32_t link_cnt = 0; 1166f1ae32a1SGerd Hoffmann active = 0; 1167f1ae32a1SGerd Hoffmann 1168f1ae32a1SGerd Hoffmann if (head == 0) 1169f1ae32a1SGerd Hoffmann return 0; 1170f1ae32a1SGerd Hoffmann 1171ab878998SLaurent Vivier for (cur = head; cur && link_cnt++ < ED_LINK_LIMIT; cur = next_ed) { 1172cf66ee8eSAlexey Kardashevskiy if (ohci_read_ed(ohci, cur, &ed)) { 1173dc1f5988SAlexey Kardashevskiy trace_usb_ohci_ed_read_error(cur); 1174cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1175f1ae32a1SGerd Hoffmann return 0; 1176f1ae32a1SGerd Hoffmann } 1177f1ae32a1SGerd Hoffmann 1178f1ae32a1SGerd Hoffmann next_ed = ed.next & OHCI_DPTR_MASK; 1179f1ae32a1SGerd Hoffmann 1180f1ae32a1SGerd Hoffmann if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) { 1181f1ae32a1SGerd Hoffmann uint32_t addr; 1182f1ae32a1SGerd Hoffmann /* Cancel pending packets for ED that have been paused. */ 1183f1ae32a1SGerd Hoffmann addr = ed.head & OHCI_DPTR_MASK; 1184f1ae32a1SGerd Hoffmann if (ohci->async_td && addr == ohci->async_td) { 1185f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1186f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1187f79738b0SHans de Goede usb_device_ep_stopped(ohci->usb_packet.ep->dev, 1188f79738b0SHans de Goede ohci->usb_packet.ep); 1189f1ae32a1SGerd Hoffmann } 1190f1ae32a1SGerd Hoffmann continue; 1191f1ae32a1SGerd Hoffmann } 1192f1ae32a1SGerd Hoffmann 1193f1ae32a1SGerd Hoffmann while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { 11943af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0, 11953af8f177SAlexey Kardashevskiy (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, 11963af8f177SAlexey Kardashevskiy ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); 11973af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt_flags( 1198f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), 1199f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, 1200f1ae32a1SGerd Hoffmann (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, 12013af8f177SAlexey Kardashevskiy OHCI_BM(ed.flags, ED_MPS)); 1202dc1f5988SAlexey Kardashevskiy 1203f1ae32a1SGerd Hoffmann active = 1; 1204f1ae32a1SGerd Hoffmann 1205f1ae32a1SGerd Hoffmann if ((ed.flags & OHCI_ED_F) == 0) { 1206f1ae32a1SGerd Hoffmann if (ohci_service_td(ohci, &ed)) 1207f1ae32a1SGerd Hoffmann break; 1208f1ae32a1SGerd Hoffmann } else { 1209f1ae32a1SGerd Hoffmann /* Handle isochronous endpoints */ 1210f1ae32a1SGerd Hoffmann if (ohci_service_iso_td(ohci, &ed, completion)) 1211f1ae32a1SGerd Hoffmann break; 1212f1ae32a1SGerd Hoffmann } 1213f1ae32a1SGerd Hoffmann } 1214f1ae32a1SGerd Hoffmann 1215cf66ee8eSAlexey Kardashevskiy if (ohci_put_ed(ohci, cur, &ed)) { 1216cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1217cf66ee8eSAlexey Kardashevskiy return 0; 1218cf66ee8eSAlexey Kardashevskiy } 1219f1ae32a1SGerd Hoffmann } 1220f1ae32a1SGerd Hoffmann 1221f1ae32a1SGerd Hoffmann return active; 1222f1ae32a1SGerd Hoffmann } 1223f1ae32a1SGerd Hoffmann 1224fd0a10cdSLaurent Vivier /* set a timer for EOF */ 1225fd0a10cdSLaurent Vivier static void ohci_eof_timer(OHCIState *ohci) 1226f1ae32a1SGerd Hoffmann { 1227bc72ad67SAlex Bligh timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time); 1228fd0a10cdSLaurent Vivier } 1229fd0a10cdSLaurent Vivier /* Set a timer for EOF and generate a SOF event */ 1230fd0a10cdSLaurent Vivier static void ohci_sof(OHCIState *ohci) 1231fd0a10cdSLaurent Vivier { 1232a60f39a4SMiguel GAIO ohci->sof_time += usb_frame_time; 1233fd0a10cdSLaurent Vivier ohci_eof_timer(ohci); 1234f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_SF); 1235f1ae32a1SGerd Hoffmann } 1236f1ae32a1SGerd Hoffmann 1237f1ae32a1SGerd Hoffmann /* Process Control and Bulk lists. */ 1238f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion) 1239f1ae32a1SGerd Hoffmann { 1240f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { 1241f1ae32a1SGerd Hoffmann if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) { 1242dc1f5988SAlexey Kardashevskiy trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur); 1243f1ae32a1SGerd Hoffmann } 1244f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) { 1245f1ae32a1SGerd Hoffmann ohci->ctrl_cur = 0; 1246f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_CLF; 1247f1ae32a1SGerd Hoffmann } 1248f1ae32a1SGerd Hoffmann } 1249f1ae32a1SGerd Hoffmann 1250f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { 1251f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) { 1252f1ae32a1SGerd Hoffmann ohci->bulk_cur = 0; 1253f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_BLF; 1254f1ae32a1SGerd Hoffmann } 1255f1ae32a1SGerd Hoffmann } 1256f1ae32a1SGerd Hoffmann } 1257f1ae32a1SGerd Hoffmann 1258f1ae32a1SGerd Hoffmann /* Do frame processing on frame boundary */ 1259f1ae32a1SGerd Hoffmann static void ohci_frame_boundary(void *opaque) 1260f1ae32a1SGerd Hoffmann { 1261f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1262f1ae32a1SGerd Hoffmann struct ohci_hcca hcca; 1263f1ae32a1SGerd Hoffmann 1264cf66ee8eSAlexey Kardashevskiy if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) { 1265dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hcca_read_error(ohci->hcca); 1266cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1267cf66ee8eSAlexey Kardashevskiy return; 1268cf66ee8eSAlexey Kardashevskiy } 1269f1ae32a1SGerd Hoffmann 1270f1ae32a1SGerd Hoffmann /* Process all the lists at the end of the frame */ 1271f1ae32a1SGerd Hoffmann if (ohci->ctl & OHCI_CTL_PLE) { 1272f1ae32a1SGerd Hoffmann int n; 1273f1ae32a1SGerd Hoffmann 1274f1ae32a1SGerd Hoffmann n = ohci->frame_number & 0x1f; 1275f1ae32a1SGerd Hoffmann ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0); 1276f1ae32a1SGerd Hoffmann } 1277f1ae32a1SGerd Hoffmann 1278f1ae32a1SGerd Hoffmann /* Cancel all pending packets if either of the lists has been disabled. */ 1279f79738b0SHans de Goede if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { 1280f79738b0SHans de Goede if (ohci->async_td) { 1281f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1282f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1283f1ae32a1SGerd Hoffmann } 1284f79738b0SHans de Goede ohci_stop_endpoints(ohci); 1285f79738b0SHans de Goede } 1286f1ae32a1SGerd Hoffmann ohci->old_ctl = ohci->ctl; 1287f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 0); 1288f1ae32a1SGerd Hoffmann 1289cf66ee8eSAlexey Kardashevskiy /* Stop if UnrecoverableError happened or ohci_sof will crash */ 1290cf66ee8eSAlexey Kardashevskiy if (ohci->intr_status & OHCI_INTR_UE) { 1291cf66ee8eSAlexey Kardashevskiy return; 1292cf66ee8eSAlexey Kardashevskiy } 1293cf66ee8eSAlexey Kardashevskiy 1294f1ae32a1SGerd Hoffmann /* Frame boundary, so do EOF stuf here */ 1295f1ae32a1SGerd Hoffmann ohci->frt = ohci->fit; 1296f1ae32a1SGerd Hoffmann 1297f1ae32a1SGerd Hoffmann /* Increment frame number and take care of endianness. */ 1298f1ae32a1SGerd Hoffmann ohci->frame_number = (ohci->frame_number + 1) & 0xffff; 1299f1ae32a1SGerd Hoffmann hcca.frame = cpu_to_le16(ohci->frame_number); 1300f1ae32a1SGerd Hoffmann 1301f1ae32a1SGerd Hoffmann if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { 1302f1ae32a1SGerd Hoffmann if (!ohci->done) 1303f1ae32a1SGerd Hoffmann abort(); 1304f1ae32a1SGerd Hoffmann if (ohci->intr & ohci->intr_status) 1305f1ae32a1SGerd Hoffmann ohci->done |= 1; 1306f1ae32a1SGerd Hoffmann hcca.done = cpu_to_le32(ohci->done); 1307f1ae32a1SGerd Hoffmann ohci->done = 0; 1308f1ae32a1SGerd Hoffmann ohci->done_count = 7; 1309f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_WD); 1310f1ae32a1SGerd Hoffmann } 1311f1ae32a1SGerd Hoffmann 1312f1ae32a1SGerd Hoffmann if (ohci->done_count != 7 && ohci->done_count != 0) 1313f1ae32a1SGerd Hoffmann ohci->done_count--; 1314f1ae32a1SGerd Hoffmann 1315f1ae32a1SGerd Hoffmann /* Do SOF stuff here */ 1316f1ae32a1SGerd Hoffmann ohci_sof(ohci); 1317f1ae32a1SGerd Hoffmann 1318f1ae32a1SGerd Hoffmann /* Writeback HCCA */ 1319cf66ee8eSAlexey Kardashevskiy if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) { 1320cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1321cf66ee8eSAlexey Kardashevskiy } 1322f1ae32a1SGerd Hoffmann } 1323f1ae32a1SGerd Hoffmann 1324f1ae32a1SGerd Hoffmann /* Start sending SOF tokens across the USB bus, lists are processed in 1325f1ae32a1SGerd Hoffmann * next frame 1326f1ae32a1SGerd Hoffmann */ 1327f1ae32a1SGerd Hoffmann static int ohci_bus_start(OHCIState *ohci) 1328f1ae32a1SGerd Hoffmann { 1329dc1f5988SAlexey Kardashevskiy trace_usb_ohci_start(ohci->name); 1330f1ae32a1SGerd Hoffmann 1331fd0a10cdSLaurent Vivier /* Delay the first SOF event by one frame time as 1332fd0a10cdSLaurent Vivier * linux driver is not ready to receive it and 1333fd0a10cdSLaurent Vivier * can meet some race conditions 1334fd0a10cdSLaurent Vivier */ 1335fd0a10cdSLaurent Vivier 1336a60f39a4SMiguel GAIO ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1337fd0a10cdSLaurent Vivier ohci_eof_timer(ohci); 1338f1ae32a1SGerd Hoffmann 1339f1ae32a1SGerd Hoffmann return 1; 1340f1ae32a1SGerd Hoffmann } 1341f1ae32a1SGerd Hoffmann 1342f1ae32a1SGerd Hoffmann /* Stop sending SOF tokens on the bus */ 134334d97308SThomas Huth void ohci_bus_stop(OHCIState *ohci) 1344f1ae32a1SGerd Hoffmann { 1345dc1f5988SAlexey Kardashevskiy trace_usb_ohci_stop(ohci->name); 1346bc72ad67SAlex Bligh timer_del(ohci->eof_timer); 1347f1ae32a1SGerd Hoffmann } 1348f1ae32a1SGerd Hoffmann 1349f1ae32a1SGerd Hoffmann /* Sets a flag in a port status register but only set it if the port is 1350f1ae32a1SGerd Hoffmann * connected, if not set ConnectStatusChange flag. If flag is enabled 1351f1ae32a1SGerd Hoffmann * return 1. 1352f1ae32a1SGerd Hoffmann */ 1353f1ae32a1SGerd Hoffmann static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) 1354f1ae32a1SGerd Hoffmann { 1355f1ae32a1SGerd Hoffmann int ret = 1; 1356f1ae32a1SGerd Hoffmann 1357f1ae32a1SGerd Hoffmann /* writing a 0 has no effect */ 1358f1ae32a1SGerd Hoffmann if (val == 0) 1359f1ae32a1SGerd Hoffmann return 0; 1360f1ae32a1SGerd Hoffmann 1361f1ae32a1SGerd Hoffmann /* If CurrentConnectStatus is cleared we set 1362f1ae32a1SGerd Hoffmann * ConnectStatusChange 1363f1ae32a1SGerd Hoffmann */ 1364f1ae32a1SGerd Hoffmann if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { 1365f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_CSC; 1366f1ae32a1SGerd Hoffmann if (ohci->rhstatus & OHCI_RHS_DRWE) { 1367f1ae32a1SGerd Hoffmann /* TODO: CSC is a wakeup event */ 1368f1ae32a1SGerd Hoffmann } 1369f1ae32a1SGerd Hoffmann return 0; 1370f1ae32a1SGerd Hoffmann } 1371f1ae32a1SGerd Hoffmann 1372f1ae32a1SGerd Hoffmann if (ohci->rhport[i].ctrl & val) 1373f1ae32a1SGerd Hoffmann ret = 0; 1374f1ae32a1SGerd Hoffmann 1375f1ae32a1SGerd Hoffmann /* set the bit */ 1376f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= val; 1377f1ae32a1SGerd Hoffmann 1378f1ae32a1SGerd Hoffmann return ret; 1379f1ae32a1SGerd Hoffmann } 1380f1ae32a1SGerd Hoffmann 1381f1ae32a1SGerd Hoffmann /* Set the frame interval - frame interval toggle is manipulated by the hcd only */ 1382f1ae32a1SGerd Hoffmann static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) 1383f1ae32a1SGerd Hoffmann { 1384f1ae32a1SGerd Hoffmann val &= OHCI_FMI_FI; 1385f1ae32a1SGerd Hoffmann 1386f1ae32a1SGerd Hoffmann if (val != ohci->fi) { 1387dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi); 1388f1ae32a1SGerd Hoffmann } 1389f1ae32a1SGerd Hoffmann 1390f1ae32a1SGerd Hoffmann ohci->fi = val; 1391f1ae32a1SGerd Hoffmann } 1392f1ae32a1SGerd Hoffmann 1393f1ae32a1SGerd Hoffmann static void ohci_port_power(OHCIState *ohci, int i, int p) 1394f1ae32a1SGerd Hoffmann { 1395f1ae32a1SGerd Hoffmann if (p) { 1396f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_PPS; 1397f1ae32a1SGerd Hoffmann } else { 1398f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| 1399f1ae32a1SGerd Hoffmann OHCI_PORT_CCS| 1400f1ae32a1SGerd Hoffmann OHCI_PORT_PSS| 1401f1ae32a1SGerd Hoffmann OHCI_PORT_PRS); 1402f1ae32a1SGerd Hoffmann } 1403f1ae32a1SGerd Hoffmann } 1404f1ae32a1SGerd Hoffmann 1405f1ae32a1SGerd Hoffmann /* Set HcControlRegister */ 1406f1ae32a1SGerd Hoffmann static void ohci_set_ctl(OHCIState *ohci, uint32_t val) 1407f1ae32a1SGerd Hoffmann { 1408f1ae32a1SGerd Hoffmann uint32_t old_state; 1409f1ae32a1SGerd Hoffmann uint32_t new_state; 1410f1ae32a1SGerd Hoffmann 1411f1ae32a1SGerd Hoffmann old_state = ohci->ctl & OHCI_CTL_HCFS; 1412f1ae32a1SGerd Hoffmann ohci->ctl = val; 1413f1ae32a1SGerd Hoffmann new_state = ohci->ctl & OHCI_CTL_HCFS; 1414f1ae32a1SGerd Hoffmann 1415f1ae32a1SGerd Hoffmann /* no state change */ 1416f1ae32a1SGerd Hoffmann if (old_state == new_state) 1417f1ae32a1SGerd Hoffmann return; 1418f1ae32a1SGerd Hoffmann 1419dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_ctl(ohci->name, new_state); 1420f1ae32a1SGerd Hoffmann switch (new_state) { 1421f1ae32a1SGerd Hoffmann case OHCI_USB_OPERATIONAL: 1422f1ae32a1SGerd Hoffmann ohci_bus_start(ohci); 1423f1ae32a1SGerd Hoffmann break; 1424f1ae32a1SGerd Hoffmann case OHCI_USB_SUSPEND: 1425f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 1426087462c7SLaurent Vivier /* clear pending SF otherwise linux driver loops in ohci_irq() */ 1427087462c7SLaurent Vivier ohci->intr_status &= ~OHCI_INTR_SF; 1428087462c7SLaurent Vivier ohci_intr_update(ohci); 1429f1ae32a1SGerd Hoffmann break; 1430f1ae32a1SGerd Hoffmann case OHCI_USB_RESUME: 1431dc1f5988SAlexey Kardashevskiy trace_usb_ohci_resume(ohci->name); 1432f1ae32a1SGerd Hoffmann break; 1433f1ae32a1SGerd Hoffmann case OHCI_USB_RESET: 14347d938fd1SHervé Poussineau ohci_roothub_reset(ohci); 1435f1ae32a1SGerd Hoffmann break; 1436f1ae32a1SGerd Hoffmann } 1437f1ae32a1SGerd Hoffmann } 1438f1ae32a1SGerd Hoffmann 1439f1ae32a1SGerd Hoffmann static uint32_t ohci_get_frame_remaining(OHCIState *ohci) 1440f1ae32a1SGerd Hoffmann { 1441f1ae32a1SGerd Hoffmann uint16_t fr; 1442f1ae32a1SGerd Hoffmann int64_t tks; 1443f1ae32a1SGerd Hoffmann 1444f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) 1445f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1446f1ae32a1SGerd Hoffmann 1447f1ae32a1SGerd Hoffmann /* Being in USB operational state guarnatees sof_time was 1448f1ae32a1SGerd Hoffmann * set already. 1449f1ae32a1SGerd Hoffmann */ 1450bc72ad67SAlex Bligh tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time; 1451a60f39a4SMiguel GAIO if (tks < 0) { 1452a60f39a4SMiguel GAIO tks = 0; 1453a60f39a4SMiguel GAIO } 1454f1ae32a1SGerd Hoffmann 1455f1ae32a1SGerd Hoffmann /* avoid muldiv if possible */ 1456f1ae32a1SGerd Hoffmann if (tks >= usb_frame_time) 1457f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1458f1ae32a1SGerd Hoffmann 1459cd1f16f9SLaurent Vivier tks = tks / usb_bit_time; 1460f1ae32a1SGerd Hoffmann fr = (uint16_t)(ohci->fi - tks); 1461f1ae32a1SGerd Hoffmann 1462f1ae32a1SGerd Hoffmann return (ohci->frt << 31) | fr; 1463f1ae32a1SGerd Hoffmann } 1464f1ae32a1SGerd Hoffmann 1465f1ae32a1SGerd Hoffmann 1466f1ae32a1SGerd Hoffmann /* Set root hub status */ 1467f1ae32a1SGerd Hoffmann static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) 1468f1ae32a1SGerd Hoffmann { 1469f1ae32a1SGerd Hoffmann uint32_t old_state; 1470f1ae32a1SGerd Hoffmann 1471f1ae32a1SGerd Hoffmann old_state = ohci->rhstatus; 1472f1ae32a1SGerd Hoffmann 1473f1ae32a1SGerd Hoffmann /* write 1 to clear OCIC */ 1474f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_OCIC) 1475f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_OCIC; 1476f1ae32a1SGerd Hoffmann 1477f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPS) { 1478f1ae32a1SGerd Hoffmann int i; 1479f1ae32a1SGerd Hoffmann 1480f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1481f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 0); 1482dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_down(); 1483f1ae32a1SGerd Hoffmann } 1484f1ae32a1SGerd Hoffmann 1485f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPSC) { 1486f1ae32a1SGerd Hoffmann int i; 1487f1ae32a1SGerd Hoffmann 1488f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1489f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 1); 1490dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_up(); 1491f1ae32a1SGerd Hoffmann } 1492f1ae32a1SGerd Hoffmann 1493f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_DRWE) 1494f1ae32a1SGerd Hoffmann ohci->rhstatus |= OHCI_RHS_DRWE; 1495f1ae32a1SGerd Hoffmann 1496f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_CRWE) 1497f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_DRWE; 1498f1ae32a1SGerd Hoffmann 1499f1ae32a1SGerd Hoffmann if (old_state != ohci->rhstatus) 1500f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1501f1ae32a1SGerd Hoffmann } 1502f1ae32a1SGerd Hoffmann 1503f1ae32a1SGerd Hoffmann /* Set root hub port status */ 1504f1ae32a1SGerd Hoffmann static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) 1505f1ae32a1SGerd Hoffmann { 1506f1ae32a1SGerd Hoffmann uint32_t old_state; 1507f1ae32a1SGerd Hoffmann OHCIPort *port; 1508f1ae32a1SGerd Hoffmann 1509f1ae32a1SGerd Hoffmann port = &ohci->rhport[portnum]; 1510f1ae32a1SGerd Hoffmann old_state = port->ctrl; 1511f1ae32a1SGerd Hoffmann 1512f1ae32a1SGerd Hoffmann /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ 1513f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_WTC) 1514f1ae32a1SGerd Hoffmann port->ctrl &= ~(val & OHCI_PORT_WTC); 1515f1ae32a1SGerd Hoffmann 1516f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_CCS) 1517f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 1518f1ae32a1SGerd Hoffmann 1519f1ae32a1SGerd Hoffmann ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); 1520f1ae32a1SGerd Hoffmann 1521f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) { 1522dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_suspend(portnum); 1523f1ae32a1SGerd Hoffmann } 1524f1ae32a1SGerd Hoffmann 1525f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { 1526dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_reset(portnum); 1527f1ae32a1SGerd Hoffmann usb_device_reset(port->port.dev); 1528f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PRS; 1529f1ae32a1SGerd Hoffmann /* ??? Should this also set OHCI_PORT_PESC. */ 1530f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; 1531f1ae32a1SGerd Hoffmann } 1532f1ae32a1SGerd Hoffmann 1533f1ae32a1SGerd Hoffmann /* Invert order here to ensure in ambiguous case, device is 1534f1ae32a1SGerd Hoffmann * powered up... 1535f1ae32a1SGerd Hoffmann */ 1536f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_LSDA) 1537f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 0); 1538f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_PPS) 1539f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 1); 1540f1ae32a1SGerd Hoffmann 1541f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) 1542f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1543f1ae32a1SGerd Hoffmann } 1544f1ae32a1SGerd Hoffmann 1545f1ae32a1SGerd Hoffmann static uint64_t ohci_mem_read(void *opaque, 1546a8170e5eSAvi Kivity hwaddr addr, 1547f1ae32a1SGerd Hoffmann unsigned size) 1548f1ae32a1SGerd Hoffmann { 1549f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1550f1ae32a1SGerd Hoffmann uint32_t retval; 1551f1ae32a1SGerd Hoffmann 1552f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1553f1ae32a1SGerd Hoffmann if (addr & 3) { 1554dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_unaligned(addr); 1555f1ae32a1SGerd Hoffmann return 0xffffffff; 1556f1ae32a1SGerd Hoffmann } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1557f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1558f1ae32a1SGerd Hoffmann retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; 1559f1ae32a1SGerd Hoffmann } else { 1560f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1561f1ae32a1SGerd Hoffmann case 0: /* HcRevision */ 1562f1ae32a1SGerd Hoffmann retval = 0x10; 1563f1ae32a1SGerd Hoffmann break; 1564f1ae32a1SGerd Hoffmann 1565f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1566f1ae32a1SGerd Hoffmann retval = ohci->ctl; 1567f1ae32a1SGerd Hoffmann break; 1568f1ae32a1SGerd Hoffmann 1569f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1570f1ae32a1SGerd Hoffmann retval = ohci->status; 1571f1ae32a1SGerd Hoffmann break; 1572f1ae32a1SGerd Hoffmann 1573f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1574f1ae32a1SGerd Hoffmann retval = ohci->intr_status; 1575f1ae32a1SGerd Hoffmann break; 1576f1ae32a1SGerd Hoffmann 1577f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1578f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1579f1ae32a1SGerd Hoffmann retval = ohci->intr; 1580f1ae32a1SGerd Hoffmann break; 1581f1ae32a1SGerd Hoffmann 1582f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1583f1ae32a1SGerd Hoffmann retval = ohci->hcca; 1584f1ae32a1SGerd Hoffmann break; 1585f1ae32a1SGerd Hoffmann 1586f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1587f1ae32a1SGerd Hoffmann retval = ohci->per_cur; 1588f1ae32a1SGerd Hoffmann break; 1589f1ae32a1SGerd Hoffmann 1590f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1591f1ae32a1SGerd Hoffmann retval = ohci->ctrl_head; 1592f1ae32a1SGerd Hoffmann break; 1593f1ae32a1SGerd Hoffmann 1594f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1595f1ae32a1SGerd Hoffmann retval = ohci->ctrl_cur; 1596f1ae32a1SGerd Hoffmann break; 1597f1ae32a1SGerd Hoffmann 1598f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1599f1ae32a1SGerd Hoffmann retval = ohci->bulk_head; 1600f1ae32a1SGerd Hoffmann break; 1601f1ae32a1SGerd Hoffmann 1602f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1603f1ae32a1SGerd Hoffmann retval = ohci->bulk_cur; 1604f1ae32a1SGerd Hoffmann break; 1605f1ae32a1SGerd Hoffmann 1606f1ae32a1SGerd Hoffmann case 12: /* HcDoneHead */ 1607f1ae32a1SGerd Hoffmann retval = ohci->done; 1608f1ae32a1SGerd Hoffmann break; 1609f1ae32a1SGerd Hoffmann 1610f1ae32a1SGerd Hoffmann case 13: /* HcFmInterretval */ 1611f1ae32a1SGerd Hoffmann retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); 1612f1ae32a1SGerd Hoffmann break; 1613f1ae32a1SGerd Hoffmann 1614f1ae32a1SGerd Hoffmann case 14: /* HcFmRemaining */ 1615f1ae32a1SGerd Hoffmann retval = ohci_get_frame_remaining(ohci); 1616f1ae32a1SGerd Hoffmann break; 1617f1ae32a1SGerd Hoffmann 1618f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1619f1ae32a1SGerd Hoffmann retval = ohci->frame_number; 1620f1ae32a1SGerd Hoffmann break; 1621f1ae32a1SGerd Hoffmann 1622f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1623f1ae32a1SGerd Hoffmann retval = ohci->pstart; 1624f1ae32a1SGerd Hoffmann break; 1625f1ae32a1SGerd Hoffmann 1626f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1627f1ae32a1SGerd Hoffmann retval = ohci->lst; 1628f1ae32a1SGerd Hoffmann break; 1629f1ae32a1SGerd Hoffmann 1630f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1631f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_a; 1632f1ae32a1SGerd Hoffmann break; 1633f1ae32a1SGerd Hoffmann 1634f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1635f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_b; 1636f1ae32a1SGerd Hoffmann break; 1637f1ae32a1SGerd Hoffmann 1638f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1639f1ae32a1SGerd Hoffmann retval = ohci->rhstatus; 1640f1ae32a1SGerd Hoffmann break; 1641f1ae32a1SGerd Hoffmann 1642f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1643f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1644f1ae32a1SGerd Hoffmann retval = ohci->hstatus & ohci->hmask; 1645f1ae32a1SGerd Hoffmann break; 1646f1ae32a1SGerd Hoffmann 1647f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1648f1ae32a1SGerd Hoffmann retval = ohci->hreset; 1649f1ae32a1SGerd Hoffmann break; 1650f1ae32a1SGerd Hoffmann 1651f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1652f1ae32a1SGerd Hoffmann retval = ohci->hmask; 1653f1ae32a1SGerd Hoffmann break; 1654f1ae32a1SGerd Hoffmann 1655f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1656f1ae32a1SGerd Hoffmann retval = ohci->htest; 1657f1ae32a1SGerd Hoffmann break; 1658f1ae32a1SGerd Hoffmann 1659f1ae32a1SGerd Hoffmann default: 1660dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_bad_offset(addr); 1661f1ae32a1SGerd Hoffmann retval = 0xffffffff; 1662f1ae32a1SGerd Hoffmann } 1663f1ae32a1SGerd Hoffmann } 1664f1ae32a1SGerd Hoffmann 1665f1ae32a1SGerd Hoffmann return retval; 1666f1ae32a1SGerd Hoffmann } 1667f1ae32a1SGerd Hoffmann 1668f1ae32a1SGerd Hoffmann static void ohci_mem_write(void *opaque, 1669a8170e5eSAvi Kivity hwaddr addr, 1670f1ae32a1SGerd Hoffmann uint64_t val, 1671f1ae32a1SGerd Hoffmann unsigned size) 1672f1ae32a1SGerd Hoffmann { 1673f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1674f1ae32a1SGerd Hoffmann 1675f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1676f1ae32a1SGerd Hoffmann if (addr & 3) { 1677dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_unaligned(addr); 1678f1ae32a1SGerd Hoffmann return; 1679f1ae32a1SGerd Hoffmann } 1680f1ae32a1SGerd Hoffmann 1681f1ae32a1SGerd Hoffmann if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1682f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1683f1ae32a1SGerd Hoffmann ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); 1684f1ae32a1SGerd Hoffmann return; 1685f1ae32a1SGerd Hoffmann } 1686f1ae32a1SGerd Hoffmann 1687f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1688f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1689f1ae32a1SGerd Hoffmann ohci_set_ctl(ohci, val); 1690f1ae32a1SGerd Hoffmann break; 1691f1ae32a1SGerd Hoffmann 1692f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1693f1ae32a1SGerd Hoffmann /* SOC is read-only */ 1694f1ae32a1SGerd Hoffmann val = (val & ~OHCI_STATUS_SOC); 1695f1ae32a1SGerd Hoffmann 1696f1ae32a1SGerd Hoffmann /* Bits written as '0' remain unchanged in the register */ 1697f1ae32a1SGerd Hoffmann ohci->status |= val; 1698f1ae32a1SGerd Hoffmann 1699f1ae32a1SGerd Hoffmann if (ohci->status & OHCI_STATUS_HCR) 17000922c3f6SHervé Poussineau ohci_soft_reset(ohci); 1701f1ae32a1SGerd Hoffmann break; 1702f1ae32a1SGerd Hoffmann 1703f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1704f1ae32a1SGerd Hoffmann ohci->intr_status &= ~val; 1705f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1706f1ae32a1SGerd Hoffmann break; 1707f1ae32a1SGerd Hoffmann 1708f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1709f1ae32a1SGerd Hoffmann ohci->intr |= val; 1710f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1711f1ae32a1SGerd Hoffmann break; 1712f1ae32a1SGerd Hoffmann 1713f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1714f1ae32a1SGerd Hoffmann ohci->intr &= ~val; 1715f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1716f1ae32a1SGerd Hoffmann break; 1717f1ae32a1SGerd Hoffmann 1718f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1719f1ae32a1SGerd Hoffmann ohci->hcca = val & OHCI_HCCA_MASK; 1720f1ae32a1SGerd Hoffmann break; 1721f1ae32a1SGerd Hoffmann 1722f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1723f1ae32a1SGerd Hoffmann /* Ignore writes to this read-only register, Linux does them */ 1724f1ae32a1SGerd Hoffmann break; 1725f1ae32a1SGerd Hoffmann 1726f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1727f1ae32a1SGerd Hoffmann ohci->ctrl_head = val & OHCI_EDPTR_MASK; 1728f1ae32a1SGerd Hoffmann break; 1729f1ae32a1SGerd Hoffmann 1730f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1731f1ae32a1SGerd Hoffmann ohci->ctrl_cur = val & OHCI_EDPTR_MASK; 1732f1ae32a1SGerd Hoffmann break; 1733f1ae32a1SGerd Hoffmann 1734f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1735f1ae32a1SGerd Hoffmann ohci->bulk_head = val & OHCI_EDPTR_MASK; 1736f1ae32a1SGerd Hoffmann break; 1737f1ae32a1SGerd Hoffmann 1738f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1739f1ae32a1SGerd Hoffmann ohci->bulk_cur = val & OHCI_EDPTR_MASK; 1740f1ae32a1SGerd Hoffmann break; 1741f1ae32a1SGerd Hoffmann 1742f1ae32a1SGerd Hoffmann case 13: /* HcFmInterval */ 1743f1ae32a1SGerd Hoffmann ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; 1744f1ae32a1SGerd Hoffmann ohci->fit = (val & OHCI_FMI_FIT) >> 31; 1745f1ae32a1SGerd Hoffmann ohci_set_frame_interval(ohci, val); 1746f1ae32a1SGerd Hoffmann break; 1747f1ae32a1SGerd Hoffmann 1748f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1749f1ae32a1SGerd Hoffmann break; 1750f1ae32a1SGerd Hoffmann 1751f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1752f1ae32a1SGerd Hoffmann ohci->pstart = val & 0xffff; 1753f1ae32a1SGerd Hoffmann break; 1754f1ae32a1SGerd Hoffmann 1755f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1756f1ae32a1SGerd Hoffmann ohci->lst = val & 0xffff; 1757f1ae32a1SGerd Hoffmann break; 1758f1ae32a1SGerd Hoffmann 1759f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1760f1ae32a1SGerd Hoffmann ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; 1761f1ae32a1SGerd Hoffmann ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; 1762f1ae32a1SGerd Hoffmann break; 1763f1ae32a1SGerd Hoffmann 1764f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1765f1ae32a1SGerd Hoffmann break; 1766f1ae32a1SGerd Hoffmann 1767f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1768f1ae32a1SGerd Hoffmann ohci_set_hub_status(ohci, val); 1769f1ae32a1SGerd Hoffmann break; 1770f1ae32a1SGerd Hoffmann 1771f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1772f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1773f1ae32a1SGerd Hoffmann ohci->hstatus &= ~(val & ohci->hmask); 17747fa96d73SGerd Hoffmann break; 1775f1ae32a1SGerd Hoffmann 1776f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1777f1ae32a1SGerd Hoffmann ohci->hreset = val & ~OHCI_HRESET_FSBIR; 1778f1ae32a1SGerd Hoffmann if (val & OHCI_HRESET_FSBIR) 177984d04e21SHervé Poussineau ohci_hard_reset(ohci); 1780f1ae32a1SGerd Hoffmann break; 1781f1ae32a1SGerd Hoffmann 1782f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1783f1ae32a1SGerd Hoffmann ohci->hmask = val; 1784f1ae32a1SGerd Hoffmann break; 1785f1ae32a1SGerd Hoffmann 1786f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1787f1ae32a1SGerd Hoffmann ohci->htest = val; 1788f1ae32a1SGerd Hoffmann break; 1789f1ae32a1SGerd Hoffmann 1790f1ae32a1SGerd Hoffmann default: 1791dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_bad_offset(addr); 1792f1ae32a1SGerd Hoffmann break; 1793f1ae32a1SGerd Hoffmann } 1794f1ae32a1SGerd Hoffmann } 1795f1ae32a1SGerd Hoffmann 1796f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev) 1797f1ae32a1SGerd Hoffmann { 1798f1ae32a1SGerd Hoffmann if (ohci->async_td && 1799f1ae32a1SGerd Hoffmann usb_packet_is_inflight(&ohci->usb_packet) && 1800f1ae32a1SGerd Hoffmann ohci->usb_packet.ep->dev == dev) { 1801f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1802f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1803f1ae32a1SGerd Hoffmann } 1804f1ae32a1SGerd Hoffmann } 1805f1ae32a1SGerd Hoffmann 1806f1ae32a1SGerd Hoffmann static const MemoryRegionOps ohci_mem_ops = { 1807f1ae32a1SGerd Hoffmann .read = ohci_mem_read, 1808f1ae32a1SGerd Hoffmann .write = ohci_mem_write, 1809f1ae32a1SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 1810f1ae32a1SGerd Hoffmann }; 1811f1ae32a1SGerd Hoffmann 1812f1ae32a1SGerd Hoffmann static USBPortOps ohci_port_ops = { 1813f1ae32a1SGerd Hoffmann .attach = ohci_attach, 1814f1ae32a1SGerd Hoffmann .detach = ohci_detach, 1815f1ae32a1SGerd Hoffmann .child_detach = ohci_child_detach, 1816f1ae32a1SGerd Hoffmann .wakeup = ohci_wakeup, 1817f1ae32a1SGerd Hoffmann .complete = ohci_async_complete_packet, 1818f1ae32a1SGerd Hoffmann }; 1819f1ae32a1SGerd Hoffmann 1820f1ae32a1SGerd Hoffmann static USBBusOps ohci_bus_ops = { 1821f1ae32a1SGerd Hoffmann }; 1822f1ae32a1SGerd Hoffmann 182334d97308SThomas Huth void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports, 182434d97308SThomas Huth dma_addr_t localmem_base, char *masterbus, 182534d97308SThomas Huth uint32_t firstport, AddressSpace *as, 182672e0c127SThomas Huth void (*ohci_die_fn)(struct OHCIState *), Error **errp) 1827f1ae32a1SGerd Hoffmann { 1828f4bbaaf5SMarkus Armbruster Error *err = NULL; 1829f1ae32a1SGerd Hoffmann int i; 1830f1ae32a1SGerd Hoffmann 1831df32fd1cSPaolo Bonzini ohci->as = as; 183272e0c127SThomas Huth ohci->ohci_die = ohci_die_fn; 18339ac6a217SDavid Gibson 1834d400fc01SThomas Huth if (num_ports > OHCI_MAX_PORTS) { 1835b9a3a4f2SLi Qiang error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)", 1836d400fc01SThomas Huth num_ports, OHCI_MAX_PORTS); 1837d400fc01SThomas Huth return; 1838d400fc01SThomas Huth } 1839d400fc01SThomas Huth 1840f1ae32a1SGerd Hoffmann if (usb_frame_time == 0) { 1841f1ae32a1SGerd Hoffmann #ifdef OHCI_TIME_WARP 184273bcb24dSRutuja Shah usb_frame_time = NANOSECONDS_PER_SECOND; 184373bcb24dSRutuja Shah usb_bit_time = NANOSECONDS_PER_SECOND / (USB_HZ / 1000); 1844f1ae32a1SGerd Hoffmann #else 184573bcb24dSRutuja Shah usb_frame_time = NANOSECONDS_PER_SECOND / 1000; 184673bcb24dSRutuja Shah if (NANOSECONDS_PER_SECOND >= USB_HZ) { 184773bcb24dSRutuja Shah usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ; 1848f1ae32a1SGerd Hoffmann } else { 1849f1ae32a1SGerd Hoffmann usb_bit_time = 1; 1850f1ae32a1SGerd Hoffmann } 1851f1ae32a1SGerd Hoffmann #endif 1852dc1f5988SAlexey Kardashevskiy trace_usb_ohci_init_time(usb_frame_time, usb_bit_time); 1853f1ae32a1SGerd Hoffmann } 1854f1ae32a1SGerd Hoffmann 1855f1ae32a1SGerd Hoffmann ohci->num_ports = num_ports; 1856f1ae32a1SGerd Hoffmann if (masterbus) { 1857f1ae32a1SGerd Hoffmann USBPort *ports[OHCI_MAX_PORTS]; 1858f1ae32a1SGerd Hoffmann for(i = 0; i < num_ports; i++) { 1859f1ae32a1SGerd Hoffmann ports[i] = &ohci->rhport[i].port; 1860f1ae32a1SGerd Hoffmann } 1861f4bbaaf5SMarkus Armbruster usb_register_companion(masterbus, ports, num_ports, 1862f1ae32a1SGerd Hoffmann firstport, ohci, &ohci_port_ops, 1863f4bbaaf5SMarkus Armbruster USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, 1864f4bbaaf5SMarkus Armbruster &err); 1865f4bbaaf5SMarkus Armbruster if (err) { 186687581feaSMarkus Armbruster error_propagate(errp, err); 186787581feaSMarkus Armbruster return; 1868f1ae32a1SGerd Hoffmann } 1869f1ae32a1SGerd Hoffmann } else { 1870c889b3a5SAndreas Färber usb_bus_new(&ohci->bus, sizeof(ohci->bus), &ohci_bus_ops, dev); 1871f1ae32a1SGerd Hoffmann for (i = 0; i < num_ports; i++) { 1872f1ae32a1SGerd Hoffmann usb_register_port(&ohci->bus, &ohci->rhport[i].port, 1873f1ae32a1SGerd Hoffmann ohci, i, &ohci_port_ops, 1874f1ae32a1SGerd Hoffmann USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); 1875f1ae32a1SGerd Hoffmann } 1876f1ae32a1SGerd Hoffmann } 1877f1ae32a1SGerd Hoffmann 187822fc860bSPaolo Bonzini memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops, 187922fc860bSPaolo Bonzini ohci, "ohci", 256); 1880f1ae32a1SGerd Hoffmann ohci->localmem_base = localmem_base; 1881f1ae32a1SGerd Hoffmann 1882f1ae32a1SGerd Hoffmann ohci->name = object_get_typename(OBJECT(dev)); 1883f1ae32a1SGerd Hoffmann usb_packet_init(&ohci->usb_packet); 1884f1ae32a1SGerd Hoffmann 1885f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1886fa1298c2SGerd Hoffmann 1887fa1298c2SGerd Hoffmann ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1888fa1298c2SGerd Hoffmann ohci_frame_boundary, ohci); 1889f1ae32a1SGerd Hoffmann } 1890f1ae32a1SGerd Hoffmann 189172e0c127SThomas Huth /** 189272e0c127SThomas Huth * A typical OHCI will stop operating and set itself into error state 189372e0c127SThomas Huth * (which can be queried by MMIO) to signal that it got an error. 1894cf66ee8eSAlexey Kardashevskiy */ 189534d97308SThomas Huth void ohci_sysbus_die(struct OHCIState *ohci) 1896cf66ee8eSAlexey Kardashevskiy { 1897dc1f5988SAlexey Kardashevskiy trace_usb_ohci_die(); 1898cf66ee8eSAlexey Kardashevskiy 1899cf66ee8eSAlexey Kardashevskiy ohci_set_interrupt(ohci, OHCI_INTR_UE); 1900cf66ee8eSAlexey Kardashevskiy ohci_bus_stop(ohci); 190172e0c127SThomas Huth } 190272e0c127SThomas Huth 1903457215ecSHu Tao static void ohci_realize_pxa(DeviceState *dev, Error **errp) 1904f1ae32a1SGerd Hoffmann { 19051aa0c0c7SHu Tao OHCISysBusState *s = SYSBUS_OHCI(dev); 1906457215ecSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 1907d7145b66SBALATON Zoltan Error *err = NULL; 1908f1ae32a1SGerd Hoffmann 1909d7145b66SBALATON Zoltan usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, 1910d7145b66SBALATON Zoltan s->masterbus, s->firstport, 191172e0c127SThomas Huth &address_space_memory, ohci_sysbus_die, &err); 1912d7145b66SBALATON Zoltan if (err) { 1913d7145b66SBALATON Zoltan error_propagate(errp, err); 1914d7145b66SBALATON Zoltan return; 1915d7145b66SBALATON Zoltan } 1916457215ecSHu Tao sysbus_init_irq(sbd, &s->ohci.irq); 1917457215ecSHu Tao sysbus_init_mmio(sbd, &s->ohci.mem); 1918f1ae32a1SGerd Hoffmann } 1919f1ae32a1SGerd Hoffmann 192088dd1b8dSGonglei static void usb_ohci_reset_sysbus(DeviceState *dev) 192188dd1b8dSGonglei { 192288dd1b8dSGonglei OHCISysBusState *s = SYSBUS_OHCI(dev); 192388dd1b8dSGonglei OHCIState *ohci = &s->ohci; 192488dd1b8dSGonglei 192584d04e21SHervé Poussineau ohci_hard_reset(ohci); 192688dd1b8dSGonglei } 192788dd1b8dSGonglei 192869e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_state_port = { 192969e25d26SAlexey Kardashevskiy .name = "ohci-core/port", 193069e25d26SAlexey Kardashevskiy .version_id = 1, 193169e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 193269e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 193369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl, OHCIPort), 193469e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 193569e25d26SAlexey Kardashevskiy }, 193669e25d26SAlexey Kardashevskiy }; 193769e25d26SAlexey Kardashevskiy 193869e25d26SAlexey Kardashevskiy static bool ohci_eof_timer_needed(void *opaque) 193969e25d26SAlexey Kardashevskiy { 194069e25d26SAlexey Kardashevskiy OHCIState *ohci = opaque; 194169e25d26SAlexey Kardashevskiy 1942fa1298c2SGerd Hoffmann return timer_pending(ohci->eof_timer); 194369e25d26SAlexey Kardashevskiy } 194469e25d26SAlexey Kardashevskiy 194569e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_eof_timer = { 194669e25d26SAlexey Kardashevskiy .name = "ohci-core/eof-timer", 194769e25d26SAlexey Kardashevskiy .version_id = 1, 194869e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 19495cd8cadaSJuan Quintela .needed = ohci_eof_timer_needed, 195069e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 1951e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(eof_timer, OHCIState), 195269e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 195369e25d26SAlexey Kardashevskiy }, 195469e25d26SAlexey Kardashevskiy }; 195569e25d26SAlexey Kardashevskiy 195634d97308SThomas Huth const VMStateDescription vmstate_ohci_state = { 195769e25d26SAlexey Kardashevskiy .name = "ohci-core", 195869e25d26SAlexey Kardashevskiy .version_id = 1, 195969e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 196069e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 196169e25d26SAlexey Kardashevskiy VMSTATE_INT64(sof_time, OHCIState), 196269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctl, OHCIState), 196369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(status, OHCIState), 196469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr_status, OHCIState), 196569e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr, OHCIState), 196669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hcca, OHCIState), 196769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_head, OHCIState), 196869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_cur, OHCIState), 196969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_head, OHCIState), 197069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_cur, OHCIState), 197169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(per_cur, OHCIState), 197269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(done, OHCIState), 197369e25d26SAlexey Kardashevskiy VMSTATE_INT32(done_count, OHCIState), 197469e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fsmps, OHCIState), 197569e25d26SAlexey Kardashevskiy VMSTATE_UINT8(fit, OHCIState), 197669e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fi, OHCIState), 197769e25d26SAlexey Kardashevskiy VMSTATE_UINT8(frt, OHCIState), 197869e25d26SAlexey Kardashevskiy VMSTATE_UINT16(frame_number, OHCIState), 197969e25d26SAlexey Kardashevskiy VMSTATE_UINT16(padding, OHCIState), 198069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(pstart, OHCIState), 198169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(lst, OHCIState), 198269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_a, OHCIState), 198369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_b, OHCIState), 198469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhstatus, OHCIState), 198569e25d26SAlexey Kardashevskiy VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0, 198669e25d26SAlexey Kardashevskiy vmstate_ohci_state_port, OHCIPort), 198769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hstatus, OHCIState), 198869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hmask, OHCIState), 198969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hreset, OHCIState), 199069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(htest, OHCIState), 199169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(old_ctl, OHCIState), 199269e25d26SAlexey Kardashevskiy VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192), 199369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(async_td, OHCIState), 199469e25d26SAlexey Kardashevskiy VMSTATE_BOOL(async_complete, OHCIState), 199569e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 199669e25d26SAlexey Kardashevskiy }, 19975cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 19985cd8cadaSJuan Quintela &vmstate_ohci_eof_timer, 19995cd8cadaSJuan Quintela NULL 200069e25d26SAlexey Kardashevskiy } 200169e25d26SAlexey Kardashevskiy }; 200269e25d26SAlexey Kardashevskiy 2003f1ae32a1SGerd Hoffmann static Property ohci_sysbus_properties[] = { 2004d7145b66SBALATON Zoltan DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus), 2005f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), 2006d7145b66SBALATON Zoltan DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0), 20076998b6c7SVijay Kumar B DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0), 2008f1ae32a1SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 2009f1ae32a1SGerd Hoffmann }; 2010f1ae32a1SGerd Hoffmann 2011f1ae32a1SGerd Hoffmann static void ohci_sysbus_class_init(ObjectClass *klass, void *data) 2012f1ae32a1SGerd Hoffmann { 2013f1ae32a1SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 2014f1ae32a1SGerd Hoffmann 2015457215ecSHu Tao dc->realize = ohci_realize_pxa; 2016125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_USB, dc->categories); 2017f1ae32a1SGerd Hoffmann dc->desc = "OHCI USB Controller"; 20184f67d30bSMarc-André Lureau device_class_set_props(dc, ohci_sysbus_properties); 201988dd1b8dSGonglei dc->reset = usb_ohci_reset_sysbus; 2020f1ae32a1SGerd Hoffmann } 2021f1ae32a1SGerd Hoffmann 20228c43a6f0SAndreas Färber static const TypeInfo ohci_sysbus_info = { 20231aa0c0c7SHu Tao .name = TYPE_SYSBUS_OHCI, 2024f1ae32a1SGerd Hoffmann .parent = TYPE_SYS_BUS_DEVICE, 2025f1ae32a1SGerd Hoffmann .instance_size = sizeof(OHCISysBusState), 2026f1ae32a1SGerd Hoffmann .class_init = ohci_sysbus_class_init, 2027f1ae32a1SGerd Hoffmann }; 2028f1ae32a1SGerd Hoffmann 2029f1ae32a1SGerd Hoffmann static void ohci_register_types(void) 2030f1ae32a1SGerd Hoffmann { 2031f1ae32a1SGerd Hoffmann type_register_static(&ohci_sysbus_info); 2032f1ae32a1SGerd Hoffmann } 2033f1ae32a1SGerd Hoffmann 2034f1ae32a1SGerd Hoffmann type_init(ohci_register_types) 2035