1f1ae32a1SGerd Hoffmann /* 2f1ae32a1SGerd Hoffmann * QEMU USB OHCI Emulation 3f1ae32a1SGerd Hoffmann * Copyright (c) 2004 Gianni Tedesco 4f1ae32a1SGerd Hoffmann * Copyright (c) 2006 CodeSourcery 5f1ae32a1SGerd Hoffmann * Copyright (c) 2006 Openedhand Ltd. 6f1ae32a1SGerd Hoffmann * 7f1ae32a1SGerd Hoffmann * This library is free software; you can redistribute it and/or 8f1ae32a1SGerd Hoffmann * modify it under the terms of the GNU Lesser General Public 9f1ae32a1SGerd Hoffmann * License as published by the Free Software Foundation; either 10f1ae32a1SGerd Hoffmann * version 2 of the License, or (at your option) any later version. 11f1ae32a1SGerd Hoffmann * 12f1ae32a1SGerd Hoffmann * This library is distributed in the hope that it will be useful, 13f1ae32a1SGerd Hoffmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 14f1ae32a1SGerd Hoffmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15f1ae32a1SGerd Hoffmann * Lesser General Public License for more details. 16f1ae32a1SGerd Hoffmann * 17f1ae32a1SGerd Hoffmann * You should have received a copy of the GNU Lesser General Public 18f1ae32a1SGerd Hoffmann * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19f1ae32a1SGerd Hoffmann * 20f1ae32a1SGerd Hoffmann * TODO: 21f1ae32a1SGerd Hoffmann * o Isochronous transfers 22f1ae32a1SGerd Hoffmann * o Allocate bandwidth in frames properly 23f1ae32a1SGerd Hoffmann * o Disable timers when nothing needs to be done, or remove timer usage 24f1ae32a1SGerd Hoffmann * all together. 25f1ae32a1SGerd Hoffmann * o BIOS work to boot from USB storage 26f1ae32a1SGerd Hoffmann */ 27f1ae32a1SGerd Hoffmann 28e532b2e0SPeter Maydell #include "qemu/osdep.h" 29f1ae32a1SGerd Hoffmann #include "hw/hw.h" 30da34e65cSMarkus Armbruster #include "qapi/error.h" 311de7afc9SPaolo Bonzini #include "qemu/timer.h" 32f1ae32a1SGerd Hoffmann #include "hw/usb.h" 33a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h" 34f1ae32a1SGerd Hoffmann #include "hw/sysbus.h" 359ac6a217SDavid Gibson #include "hw/qdev-dma.h" 36dc1f5988SAlexey Kardashevskiy #include "trace.h" 37f1ae32a1SGerd Hoffmann 38f1ae32a1SGerd Hoffmann /* This causes frames to occur 1000x slower */ 39f1ae32a1SGerd Hoffmann //#define OHCI_TIME_WARP 1 40f1ae32a1SGerd Hoffmann 41f1ae32a1SGerd Hoffmann /* Number of Downstream Ports on the root hub. */ 42f1ae32a1SGerd Hoffmann 43f1ae32a1SGerd Hoffmann #define OHCI_MAX_PORTS 15 44f1ae32a1SGerd Hoffmann 45ab6b1105SGerd Hoffmann #define ED_LINK_LIMIT 32 4695ed5693SLi Qiang 47f1ae32a1SGerd Hoffmann static int64_t usb_frame_time; 48f1ae32a1SGerd Hoffmann static int64_t usb_bit_time; 49f1ae32a1SGerd Hoffmann 50f1ae32a1SGerd Hoffmann typedef struct OHCIPort { 51f1ae32a1SGerd Hoffmann USBPort port; 52f1ae32a1SGerd Hoffmann uint32_t ctrl; 53f1ae32a1SGerd Hoffmann } OHCIPort; 54f1ae32a1SGerd Hoffmann 55f1ae32a1SGerd Hoffmann typedef struct { 56f1ae32a1SGerd Hoffmann USBBus bus; 57f1ae32a1SGerd Hoffmann qemu_irq irq; 58f1ae32a1SGerd Hoffmann MemoryRegion mem; 59df32fd1cSPaolo Bonzini AddressSpace *as; 60f1ae32a1SGerd Hoffmann int num_ports; 61f1ae32a1SGerd Hoffmann const char *name; 62f1ae32a1SGerd Hoffmann 63f1ae32a1SGerd Hoffmann QEMUTimer *eof_timer; 64f1ae32a1SGerd Hoffmann int64_t sof_time; 65f1ae32a1SGerd Hoffmann 66f1ae32a1SGerd Hoffmann /* OHCI state */ 67f1ae32a1SGerd Hoffmann /* Control partition */ 68f1ae32a1SGerd Hoffmann uint32_t ctl, status; 69f1ae32a1SGerd Hoffmann uint32_t intr_status; 70f1ae32a1SGerd Hoffmann uint32_t intr; 71f1ae32a1SGerd Hoffmann 72f1ae32a1SGerd Hoffmann /* memory pointer partition */ 73f1ae32a1SGerd Hoffmann uint32_t hcca; 74f1ae32a1SGerd Hoffmann uint32_t ctrl_head, ctrl_cur; 75f1ae32a1SGerd Hoffmann uint32_t bulk_head, bulk_cur; 76f1ae32a1SGerd Hoffmann uint32_t per_cur; 77f1ae32a1SGerd Hoffmann uint32_t done; 7869e25d26SAlexey Kardashevskiy int32_t done_count; 79f1ae32a1SGerd Hoffmann 80f1ae32a1SGerd Hoffmann /* Frame counter partition */ 8169e25d26SAlexey Kardashevskiy uint16_t fsmps; 8269e25d26SAlexey Kardashevskiy uint8_t fit; 8369e25d26SAlexey Kardashevskiy uint16_t fi; 8469e25d26SAlexey Kardashevskiy uint8_t frt; 85f1ae32a1SGerd Hoffmann uint16_t frame_number; 86f1ae32a1SGerd Hoffmann uint16_t padding; 87f1ae32a1SGerd Hoffmann uint32_t pstart; 88f1ae32a1SGerd Hoffmann uint32_t lst; 89f1ae32a1SGerd Hoffmann 90f1ae32a1SGerd Hoffmann /* Root Hub partition */ 91f1ae32a1SGerd Hoffmann uint32_t rhdesc_a, rhdesc_b; 92f1ae32a1SGerd Hoffmann uint32_t rhstatus; 93f1ae32a1SGerd Hoffmann OHCIPort rhport[OHCI_MAX_PORTS]; 94f1ae32a1SGerd Hoffmann 95f1ae32a1SGerd Hoffmann /* PXA27x Non-OHCI events */ 96f1ae32a1SGerd Hoffmann uint32_t hstatus; 97f1ae32a1SGerd Hoffmann uint32_t hmask; 98f1ae32a1SGerd Hoffmann uint32_t hreset; 99f1ae32a1SGerd Hoffmann uint32_t htest; 100f1ae32a1SGerd Hoffmann 101f1ae32a1SGerd Hoffmann /* SM501 local memory offset */ 1029ac6a217SDavid Gibson dma_addr_t localmem_base; 103f1ae32a1SGerd Hoffmann 104f1ae32a1SGerd Hoffmann /* Active packets. */ 105f1ae32a1SGerd Hoffmann uint32_t old_ctl; 106f1ae32a1SGerd Hoffmann USBPacket usb_packet; 107f1ae32a1SGerd Hoffmann uint8_t usb_buf[8192]; 108f1ae32a1SGerd Hoffmann uint32_t async_td; 10969e25d26SAlexey Kardashevskiy bool async_complete; 110f1ae32a1SGerd Hoffmann 111f1ae32a1SGerd Hoffmann } OHCIState; 112f1ae32a1SGerd Hoffmann 113f1ae32a1SGerd Hoffmann /* Host Controller Communications Area */ 114f1ae32a1SGerd Hoffmann struct ohci_hcca { 115f1ae32a1SGerd Hoffmann uint32_t intr[32]; 116f1ae32a1SGerd Hoffmann uint16_t frame, pad; 117f1ae32a1SGerd Hoffmann uint32_t done; 118f1ae32a1SGerd Hoffmann }; 11986e18caeSWei Yang #define HCCA_WRITEBACK_OFFSET offsetof(struct ohci_hcca, frame) 12086e18caeSWei Yang #define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */ 12186e18caeSWei Yang 12286e18caeSWei Yang #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head) 12386e18caeSWei Yang #define ED_WBACK_SIZE 4 124f1ae32a1SGerd Hoffmann 125f1ae32a1SGerd Hoffmann static void ohci_bus_stop(OHCIState *ohci); 126f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); 127f1ae32a1SGerd Hoffmann 128f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Endpoint Desciptor. */ 129f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_SHIFT 0 130f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT) 131f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_SHIFT 7 132f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT) 133f1ae32a1SGerd Hoffmann #define OHCI_ED_D_SHIFT 11 134f1ae32a1SGerd Hoffmann #define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT) 135f1ae32a1SGerd Hoffmann #define OHCI_ED_S (1<<13) 136f1ae32a1SGerd Hoffmann #define OHCI_ED_K (1<<14) 137f1ae32a1SGerd Hoffmann #define OHCI_ED_F (1<<15) 138f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_SHIFT 16 139f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_MASK (0x7ff<<OHCI_ED_MPS_SHIFT) 140f1ae32a1SGerd Hoffmann 141f1ae32a1SGerd Hoffmann /* Flags in the head field of an Endpoint Desciptor. */ 142f1ae32a1SGerd Hoffmann #define OHCI_ED_H 1 143f1ae32a1SGerd Hoffmann #define OHCI_ED_C 2 144f1ae32a1SGerd Hoffmann 145f1ae32a1SGerd Hoffmann /* Bitfields for the first word of a Transfer Desciptor. */ 146f1ae32a1SGerd Hoffmann #define OHCI_TD_R (1<<18) 147f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_SHIFT 19 148f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT) 149f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_SHIFT 21 150f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT) 151f1ae32a1SGerd Hoffmann #define OHCI_TD_T0 (1<<24) 152f1ae32a1SGerd Hoffmann #define OHCI_TD_T1 (1<<25) 153f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_SHIFT 26 154f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT) 155f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_SHIFT 28 156f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT) 157f1ae32a1SGerd Hoffmann 158f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Isochronous Transfer Desciptor. */ 159f1ae32a1SGerd Hoffmann /* CC & DI - same as in the General Transfer Desciptor */ 160f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_SHIFT 0 161f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT) 162f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_SHIFT 24 163f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT) 164f1ae32a1SGerd Hoffmann 165f1ae32a1SGerd Hoffmann /* Isochronous Transfer Desciptor - Offset / PacketStatusWord */ 166f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_SHIFT 12 167f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT) 168f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_SHIFT 0 169f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT) 170f1ae32a1SGerd Hoffmann 171f1ae32a1SGerd Hoffmann #define OHCI_PAGE_MASK 0xfffff000 172f1ae32a1SGerd Hoffmann #define OHCI_OFFSET_MASK 0xfff 173f1ae32a1SGerd Hoffmann 174f1ae32a1SGerd Hoffmann #define OHCI_DPTR_MASK 0xfffffff0 175f1ae32a1SGerd Hoffmann 176f1ae32a1SGerd Hoffmann #define OHCI_BM(val, field) \ 177f1ae32a1SGerd Hoffmann (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT) 178f1ae32a1SGerd Hoffmann 179f1ae32a1SGerd Hoffmann #define OHCI_SET_BM(val, field, newval) do { \ 180f1ae32a1SGerd Hoffmann val &= ~OHCI_##field##_MASK; \ 181f1ae32a1SGerd Hoffmann val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ 182f1ae32a1SGerd Hoffmann } while(0) 183f1ae32a1SGerd Hoffmann 184f1ae32a1SGerd Hoffmann /* endpoint descriptor */ 185f1ae32a1SGerd Hoffmann struct ohci_ed { 186f1ae32a1SGerd Hoffmann uint32_t flags; 187f1ae32a1SGerd Hoffmann uint32_t tail; 188f1ae32a1SGerd Hoffmann uint32_t head; 189f1ae32a1SGerd Hoffmann uint32_t next; 190f1ae32a1SGerd Hoffmann }; 191f1ae32a1SGerd Hoffmann 192f1ae32a1SGerd Hoffmann /* General transfer descriptor */ 193f1ae32a1SGerd Hoffmann struct ohci_td { 194f1ae32a1SGerd Hoffmann uint32_t flags; 195f1ae32a1SGerd Hoffmann uint32_t cbp; 196f1ae32a1SGerd Hoffmann uint32_t next; 197f1ae32a1SGerd Hoffmann uint32_t be; 198f1ae32a1SGerd Hoffmann }; 199f1ae32a1SGerd Hoffmann 200f1ae32a1SGerd Hoffmann /* Isochronous transfer descriptor */ 201f1ae32a1SGerd Hoffmann struct ohci_iso_td { 202f1ae32a1SGerd Hoffmann uint32_t flags; 203f1ae32a1SGerd Hoffmann uint32_t bp; 204f1ae32a1SGerd Hoffmann uint32_t next; 205f1ae32a1SGerd Hoffmann uint32_t be; 206f1ae32a1SGerd Hoffmann uint16_t offset[8]; 207f1ae32a1SGerd Hoffmann }; 208f1ae32a1SGerd Hoffmann 209f1ae32a1SGerd Hoffmann #define USB_HZ 12000000 210f1ae32a1SGerd Hoffmann 211f1ae32a1SGerd Hoffmann /* OHCI Local stuff */ 212f1ae32a1SGerd Hoffmann #define OHCI_CTL_CBSR ((1<<0)|(1<<1)) 213f1ae32a1SGerd Hoffmann #define OHCI_CTL_PLE (1<<2) 214f1ae32a1SGerd Hoffmann #define OHCI_CTL_IE (1<<3) 215f1ae32a1SGerd Hoffmann #define OHCI_CTL_CLE (1<<4) 216f1ae32a1SGerd Hoffmann #define OHCI_CTL_BLE (1<<5) 217f1ae32a1SGerd Hoffmann #define OHCI_CTL_HCFS ((1<<6)|(1<<7)) 218f1ae32a1SGerd Hoffmann #define OHCI_USB_RESET 0x00 219f1ae32a1SGerd Hoffmann #define OHCI_USB_RESUME 0x40 220f1ae32a1SGerd Hoffmann #define OHCI_USB_OPERATIONAL 0x80 221f1ae32a1SGerd Hoffmann #define OHCI_USB_SUSPEND 0xc0 222f1ae32a1SGerd Hoffmann #define OHCI_CTL_IR (1<<8) 223f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWC (1<<9) 224f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWE (1<<10) 225f1ae32a1SGerd Hoffmann 226f1ae32a1SGerd Hoffmann #define OHCI_STATUS_HCR (1<<0) 227f1ae32a1SGerd Hoffmann #define OHCI_STATUS_CLF (1<<1) 228f1ae32a1SGerd Hoffmann #define OHCI_STATUS_BLF (1<<2) 229f1ae32a1SGerd Hoffmann #define OHCI_STATUS_OCR (1<<3) 230f1ae32a1SGerd Hoffmann #define OHCI_STATUS_SOC ((1<<6)|(1<<7)) 231f1ae32a1SGerd Hoffmann 23200b01793SPeter Maydell #define OHCI_INTR_SO (1U<<0) /* Scheduling overrun */ 23300b01793SPeter Maydell #define OHCI_INTR_WD (1U<<1) /* HcDoneHead writeback */ 23400b01793SPeter Maydell #define OHCI_INTR_SF (1U<<2) /* Start of frame */ 23500b01793SPeter Maydell #define OHCI_INTR_RD (1U<<3) /* Resume detect */ 23600b01793SPeter Maydell #define OHCI_INTR_UE (1U<<4) /* Unrecoverable error */ 23700b01793SPeter Maydell #define OHCI_INTR_FNO (1U<<5) /* Frame number overflow */ 23800b01793SPeter Maydell #define OHCI_INTR_RHSC (1U<<6) /* Root hub status change */ 23900b01793SPeter Maydell #define OHCI_INTR_OC (1U<<30) /* Ownership change */ 24000b01793SPeter Maydell #define OHCI_INTR_MIE (1U<<31) /* Master Interrupt Enable */ 241f1ae32a1SGerd Hoffmann 242f1ae32a1SGerd Hoffmann #define OHCI_HCCA_SIZE 0x100 243f1ae32a1SGerd Hoffmann #define OHCI_HCCA_MASK 0xffffff00 244f1ae32a1SGerd Hoffmann 245f1ae32a1SGerd Hoffmann #define OHCI_EDPTR_MASK 0xfffffff0 246f1ae32a1SGerd Hoffmann 247f1ae32a1SGerd Hoffmann #define OHCI_FMI_FI 0x00003fff 248f1ae32a1SGerd Hoffmann #define OHCI_FMI_FSMPS 0xffff0000 249f1ae32a1SGerd Hoffmann #define OHCI_FMI_FIT 0x80000000 250f1ae32a1SGerd Hoffmann 25100b01793SPeter Maydell #define OHCI_FR_RT (1U<<31) 252f1ae32a1SGerd Hoffmann 253f1ae32a1SGerd Hoffmann #define OHCI_LS_THRESH 0x628 254f1ae32a1SGerd Hoffmann 255f1ae32a1SGerd Hoffmann #define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ 256f1ae32a1SGerd Hoffmann #define OHCI_RHA_PSM (1<<8) 257f1ae32a1SGerd Hoffmann #define OHCI_RHA_NPS (1<<9) 258f1ae32a1SGerd Hoffmann #define OHCI_RHA_DT (1<<10) 259f1ae32a1SGerd Hoffmann #define OHCI_RHA_OCPM (1<<11) 260f1ae32a1SGerd Hoffmann #define OHCI_RHA_NOCP (1<<12) 261f1ae32a1SGerd Hoffmann #define OHCI_RHA_POTPGT_MASK 0xff000000 262f1ae32a1SGerd Hoffmann 26300b01793SPeter Maydell #define OHCI_RHS_LPS (1U<<0) 26400b01793SPeter Maydell #define OHCI_RHS_OCI (1U<<1) 26500b01793SPeter Maydell #define OHCI_RHS_DRWE (1U<<15) 26600b01793SPeter Maydell #define OHCI_RHS_LPSC (1U<<16) 26700b01793SPeter Maydell #define OHCI_RHS_OCIC (1U<<17) 26800b01793SPeter Maydell #define OHCI_RHS_CRWE (1U<<31) 269f1ae32a1SGerd Hoffmann 270f1ae32a1SGerd Hoffmann #define OHCI_PORT_CCS (1<<0) 271f1ae32a1SGerd Hoffmann #define OHCI_PORT_PES (1<<1) 272f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSS (1<<2) 273f1ae32a1SGerd Hoffmann #define OHCI_PORT_POCI (1<<3) 274f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRS (1<<4) 275f1ae32a1SGerd Hoffmann #define OHCI_PORT_PPS (1<<8) 276f1ae32a1SGerd Hoffmann #define OHCI_PORT_LSDA (1<<9) 277f1ae32a1SGerd Hoffmann #define OHCI_PORT_CSC (1<<16) 278f1ae32a1SGerd Hoffmann #define OHCI_PORT_PESC (1<<17) 279f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSSC (1<<18) 280f1ae32a1SGerd Hoffmann #define OHCI_PORT_OCIC (1<<19) 281f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRSC (1<<20) 282f1ae32a1SGerd Hoffmann #define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ 283f1ae32a1SGerd Hoffmann |OHCI_PORT_OCIC|OHCI_PORT_PRSC) 284f1ae32a1SGerd Hoffmann 285f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_SETUP 0x0 286f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_OUT 0x1 287f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_IN 0x2 288f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_RESERVED 0x3 289f1ae32a1SGerd Hoffmann 290f1ae32a1SGerd Hoffmann #define OHCI_CC_NOERROR 0x0 291f1ae32a1SGerd Hoffmann #define OHCI_CC_CRC 0x1 292f1ae32a1SGerd Hoffmann #define OHCI_CC_BITSTUFFING 0x2 293f1ae32a1SGerd Hoffmann #define OHCI_CC_DATATOGGLEMISMATCH 0x3 294f1ae32a1SGerd Hoffmann #define OHCI_CC_STALL 0x4 295f1ae32a1SGerd Hoffmann #define OHCI_CC_DEVICENOTRESPONDING 0x5 296f1ae32a1SGerd Hoffmann #define OHCI_CC_PIDCHECKFAILURE 0x6 297f1ae32a1SGerd Hoffmann #define OHCI_CC_UNDEXPETEDPID 0x7 298f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAOVERRUN 0x8 299f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAUNDERRUN 0x9 300f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFEROVERRUN 0xc 301f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFERUNDERRUN 0xd 302f1ae32a1SGerd Hoffmann 303f1ae32a1SGerd Hoffmann #define OHCI_HRESET_FSBIR (1 << 0) 304f1ae32a1SGerd Hoffmann 305cf66ee8eSAlexey Kardashevskiy static void ohci_die(OHCIState *ohci); 306cf66ee8eSAlexey Kardashevskiy 307f1ae32a1SGerd Hoffmann /* Update IRQ levels */ 308f1ae32a1SGerd Hoffmann static inline void ohci_intr_update(OHCIState *ohci) 309f1ae32a1SGerd Hoffmann { 310f1ae32a1SGerd Hoffmann int level = 0; 311f1ae32a1SGerd Hoffmann 312f1ae32a1SGerd Hoffmann if ((ohci->intr & OHCI_INTR_MIE) && 313f1ae32a1SGerd Hoffmann (ohci->intr_status & ohci->intr)) 314f1ae32a1SGerd Hoffmann level = 1; 315f1ae32a1SGerd Hoffmann 316f1ae32a1SGerd Hoffmann qemu_set_irq(ohci->irq, level); 317f1ae32a1SGerd Hoffmann } 318f1ae32a1SGerd Hoffmann 319f1ae32a1SGerd Hoffmann /* Set an interrupt */ 320f1ae32a1SGerd Hoffmann static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) 321f1ae32a1SGerd Hoffmann { 322f1ae32a1SGerd Hoffmann ohci->intr_status |= intr; 323f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 324f1ae32a1SGerd Hoffmann } 325f1ae32a1SGerd Hoffmann 326f1ae32a1SGerd Hoffmann /* Attach or detach a device on a root hub port. */ 327f1ae32a1SGerd Hoffmann static void ohci_attach(USBPort *port1) 328f1ae32a1SGerd Hoffmann { 329f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 330f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 331f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 332f1ae32a1SGerd Hoffmann 333f1ae32a1SGerd Hoffmann /* set connect status */ 334f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; 335f1ae32a1SGerd Hoffmann 336f1ae32a1SGerd Hoffmann /* update speed */ 337f1ae32a1SGerd Hoffmann if (port->port.dev->speed == USB_SPEED_LOW) { 338f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_LSDA; 339f1ae32a1SGerd Hoffmann } else { 340f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_LSDA; 341f1ae32a1SGerd Hoffmann } 342f1ae32a1SGerd Hoffmann 343f1ae32a1SGerd Hoffmann /* notify of remote-wakeup */ 344f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 345f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RD); 346f1ae32a1SGerd Hoffmann } 347f1ae32a1SGerd Hoffmann 348dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_attach(port1->index); 349f1ae32a1SGerd Hoffmann 350f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 351f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 352f1ae32a1SGerd Hoffmann } 353f1ae32a1SGerd Hoffmann } 354f1ae32a1SGerd Hoffmann 355f1ae32a1SGerd Hoffmann static void ohci_detach(USBPort *port1) 356f1ae32a1SGerd Hoffmann { 357f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 358f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 359f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 360f1ae32a1SGerd Hoffmann 361f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, port1->dev); 362f1ae32a1SGerd Hoffmann 363f1ae32a1SGerd Hoffmann /* set connect status */ 364f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_CCS) { 365f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_CCS; 366f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CSC; 367f1ae32a1SGerd Hoffmann } 368f1ae32a1SGerd Hoffmann /* disable port */ 369f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PES) { 370f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 371f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PESC; 372f1ae32a1SGerd Hoffmann } 373dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_detach(port1->index); 374f1ae32a1SGerd Hoffmann 375f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 376f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 377f1ae32a1SGerd Hoffmann } 378f1ae32a1SGerd Hoffmann } 379f1ae32a1SGerd Hoffmann 380f1ae32a1SGerd Hoffmann static void ohci_wakeup(USBPort *port1) 381f1ae32a1SGerd Hoffmann { 382f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 383f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 384f1ae32a1SGerd Hoffmann uint32_t intr = 0; 385f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PSS) { 386dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_wakeup(port1->index); 387f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PSSC; 388f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PSS; 389f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RHSC; 390f1ae32a1SGerd Hoffmann } 391f1ae32a1SGerd Hoffmann /* Note that the controller can be suspended even if this port is not */ 392f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 393dc1f5988SAlexey Kardashevskiy trace_usb_ohci_remote_wakeup(s->name); 394f1ae32a1SGerd Hoffmann /* This is the one state transition the controller can do by itself */ 395f1ae32a1SGerd Hoffmann s->ctl &= ~OHCI_CTL_HCFS; 396f1ae32a1SGerd Hoffmann s->ctl |= OHCI_USB_RESUME; 397f1ae32a1SGerd Hoffmann /* In suspend mode only ResumeDetected is possible, not RHSC: 398f1ae32a1SGerd Hoffmann * see the OHCI spec 5.1.2.3. 399f1ae32a1SGerd Hoffmann */ 400f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RD; 401f1ae32a1SGerd Hoffmann } 402f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, intr); 403f1ae32a1SGerd Hoffmann } 404f1ae32a1SGerd Hoffmann 405f1ae32a1SGerd Hoffmann static void ohci_child_detach(USBPort *port1, USBDevice *child) 406f1ae32a1SGerd Hoffmann { 407f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 408f1ae32a1SGerd Hoffmann 409f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, child); 410f1ae32a1SGerd Hoffmann } 411f1ae32a1SGerd Hoffmann 412f1ae32a1SGerd Hoffmann static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr) 413f1ae32a1SGerd Hoffmann { 414f1ae32a1SGerd Hoffmann USBDevice *dev; 415f1ae32a1SGerd Hoffmann int i; 416f1ae32a1SGerd Hoffmann 417f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) { 418f1ae32a1SGerd Hoffmann if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) { 419f1ae32a1SGerd Hoffmann continue; 420f1ae32a1SGerd Hoffmann } 421f1ae32a1SGerd Hoffmann dev = usb_find_device(&ohci->rhport[i].port, addr); 422f1ae32a1SGerd Hoffmann if (dev != NULL) { 423f1ae32a1SGerd Hoffmann return dev; 424f1ae32a1SGerd Hoffmann } 425f1ae32a1SGerd Hoffmann } 426f1ae32a1SGerd Hoffmann return NULL; 427f1ae32a1SGerd Hoffmann } 428f1ae32a1SGerd Hoffmann 429f79738b0SHans de Goede static void ohci_stop_endpoints(OHCIState *ohci) 430f79738b0SHans de Goede { 431f79738b0SHans de Goede USBDevice *dev; 432f79738b0SHans de Goede int i, j; 433f79738b0SHans de Goede 434f79738b0SHans de Goede for (i = 0; i < ohci->num_ports; i++) { 435f79738b0SHans de Goede dev = ohci->rhport[i].port.dev; 436f79738b0SHans de Goede if (dev && dev->attached) { 437f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_ctl); 438f79738b0SHans de Goede for (j = 0; j < USB_MAX_ENDPOINTS; j++) { 439f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_in[j]); 440f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_out[j]); 441f79738b0SHans de Goede } 442f79738b0SHans de Goede } 443f79738b0SHans de Goede } 444f79738b0SHans de Goede } 445f79738b0SHans de Goede 44684d04e21SHervé Poussineau static void ohci_roothub_reset(OHCIState *ohci) 447f1ae32a1SGerd Hoffmann { 448f1ae32a1SGerd Hoffmann OHCIPort *port; 449f1ae32a1SGerd Hoffmann int i; 450f1ae32a1SGerd Hoffmann 451f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 45284d04e21SHervé Poussineau ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; 45384d04e21SHervé Poussineau ohci->rhdesc_b = 0x0; /* Impl. specific */ 45484d04e21SHervé Poussineau ohci->rhstatus = 0; 45584d04e21SHervé Poussineau 45684d04e21SHervé Poussineau for (i = 0; i < ohci->num_ports; i++) { 45784d04e21SHervé Poussineau port = &ohci->rhport[i]; 45884d04e21SHervé Poussineau port->ctrl = 0; 45984d04e21SHervé Poussineau if (port->port.dev && port->port.dev->attached) { 46084d04e21SHervé Poussineau usb_port_reset(&port->port); 46184d04e21SHervé Poussineau } 46284d04e21SHervé Poussineau } 46384d04e21SHervé Poussineau if (ohci->async_td) { 46484d04e21SHervé Poussineau usb_cancel_packet(&ohci->usb_packet); 46584d04e21SHervé Poussineau ohci->async_td = 0; 46684d04e21SHervé Poussineau } 46784d04e21SHervé Poussineau ohci_stop_endpoints(ohci); 46884d04e21SHervé Poussineau } 46984d04e21SHervé Poussineau 47084d04e21SHervé Poussineau /* Reset the controller */ 47184d04e21SHervé Poussineau static void ohci_soft_reset(OHCIState *ohci) 47284d04e21SHervé Poussineau { 47384d04e21SHervé Poussineau trace_usb_ohci_reset(ohci->name); 47484d04e21SHervé Poussineau 47584d04e21SHervé Poussineau ohci_bus_stop(ohci); 47684d04e21SHervé Poussineau ohci->ctl = (ohci->ctl & OHCI_CTL_IR) | OHCI_USB_SUSPEND; 477f1ae32a1SGerd Hoffmann ohci->old_ctl = 0; 478f1ae32a1SGerd Hoffmann ohci->status = 0; 479f1ae32a1SGerd Hoffmann ohci->intr_status = 0; 480f1ae32a1SGerd Hoffmann ohci->intr = OHCI_INTR_MIE; 481f1ae32a1SGerd Hoffmann 482f1ae32a1SGerd Hoffmann ohci->hcca = 0; 483f1ae32a1SGerd Hoffmann ohci->ctrl_head = ohci->ctrl_cur = 0; 484f1ae32a1SGerd Hoffmann ohci->bulk_head = ohci->bulk_cur = 0; 485f1ae32a1SGerd Hoffmann ohci->per_cur = 0; 486f1ae32a1SGerd Hoffmann ohci->done = 0; 487f1ae32a1SGerd Hoffmann ohci->done_count = 7; 488f1ae32a1SGerd Hoffmann 489f1ae32a1SGerd Hoffmann /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? 490f1ae32a1SGerd Hoffmann * I took the value linux sets ... 491f1ae32a1SGerd Hoffmann */ 492f1ae32a1SGerd Hoffmann ohci->fsmps = 0x2778; 493f1ae32a1SGerd Hoffmann ohci->fi = 0x2edf; 494f1ae32a1SGerd Hoffmann ohci->fit = 0; 495f1ae32a1SGerd Hoffmann ohci->frt = 0; 496f1ae32a1SGerd Hoffmann ohci->frame_number = 0; 497f1ae32a1SGerd Hoffmann ohci->pstart = 0; 498f1ae32a1SGerd Hoffmann ohci->lst = OHCI_LS_THRESH; 49984d04e21SHervé Poussineau } 500f1ae32a1SGerd Hoffmann 50184d04e21SHervé Poussineau static void ohci_hard_reset(OHCIState *ohci) 502f1ae32a1SGerd Hoffmann { 50384d04e21SHervé Poussineau ohci_soft_reset(ohci); 50484d04e21SHervé Poussineau ohci->ctl = 0; 50584d04e21SHervé Poussineau ohci_roothub_reset(ohci); 506f1ae32a1SGerd Hoffmann } 507f1ae32a1SGerd Hoffmann 508f1ae32a1SGerd Hoffmann /* Get an array of dwords from main memory */ 509f1ae32a1SGerd Hoffmann static inline int get_dwords(OHCIState *ohci, 5109ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 511f1ae32a1SGerd Hoffmann { 512f1ae32a1SGerd Hoffmann int i; 513f1ae32a1SGerd Hoffmann 514f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 515f1ae32a1SGerd Hoffmann 516f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 517cf66ee8eSAlexey Kardashevskiy if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { 518cf66ee8eSAlexey Kardashevskiy return -1; 519cf66ee8eSAlexey Kardashevskiy } 520f1ae32a1SGerd Hoffmann *buf = le32_to_cpu(*buf); 521f1ae32a1SGerd Hoffmann } 522f1ae32a1SGerd Hoffmann 523cf66ee8eSAlexey Kardashevskiy return 0; 524f1ae32a1SGerd Hoffmann } 525f1ae32a1SGerd Hoffmann 526f1ae32a1SGerd Hoffmann /* Put an array of dwords in to main memory */ 527f1ae32a1SGerd Hoffmann static inline int put_dwords(OHCIState *ohci, 5289ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 529f1ae32a1SGerd Hoffmann { 530f1ae32a1SGerd Hoffmann int i; 531f1ae32a1SGerd Hoffmann 532f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 533f1ae32a1SGerd Hoffmann 534f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 535f1ae32a1SGerd Hoffmann uint32_t tmp = cpu_to_le32(*buf); 536cf66ee8eSAlexey Kardashevskiy if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { 537cf66ee8eSAlexey Kardashevskiy return -1; 538cf66ee8eSAlexey Kardashevskiy } 539f1ae32a1SGerd Hoffmann } 540f1ae32a1SGerd Hoffmann 541cf66ee8eSAlexey Kardashevskiy return 0; 542f1ae32a1SGerd Hoffmann } 543f1ae32a1SGerd Hoffmann 544f1ae32a1SGerd Hoffmann /* Get an array of words from main memory */ 545f1ae32a1SGerd Hoffmann static inline int get_words(OHCIState *ohci, 5469ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 547f1ae32a1SGerd Hoffmann { 548f1ae32a1SGerd Hoffmann int i; 549f1ae32a1SGerd Hoffmann 550f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 551f1ae32a1SGerd Hoffmann 552f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 553cf66ee8eSAlexey Kardashevskiy if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { 554cf66ee8eSAlexey Kardashevskiy return -1; 555cf66ee8eSAlexey Kardashevskiy } 556f1ae32a1SGerd Hoffmann *buf = le16_to_cpu(*buf); 557f1ae32a1SGerd Hoffmann } 558f1ae32a1SGerd Hoffmann 559cf66ee8eSAlexey Kardashevskiy return 0; 560f1ae32a1SGerd Hoffmann } 561f1ae32a1SGerd Hoffmann 562f1ae32a1SGerd Hoffmann /* Put an array of words in to main memory */ 563f1ae32a1SGerd Hoffmann static inline int put_words(OHCIState *ohci, 5649ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 565f1ae32a1SGerd Hoffmann { 566f1ae32a1SGerd Hoffmann int i; 567f1ae32a1SGerd Hoffmann 568f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 569f1ae32a1SGerd Hoffmann 570f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 571f1ae32a1SGerd Hoffmann uint16_t tmp = cpu_to_le16(*buf); 572cf66ee8eSAlexey Kardashevskiy if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { 573cf66ee8eSAlexey Kardashevskiy return -1; 574cf66ee8eSAlexey Kardashevskiy } 575f1ae32a1SGerd Hoffmann } 576f1ae32a1SGerd Hoffmann 577cf66ee8eSAlexey Kardashevskiy return 0; 578f1ae32a1SGerd Hoffmann } 579f1ae32a1SGerd Hoffmann 580f1ae32a1SGerd Hoffmann static inline int ohci_read_ed(OHCIState *ohci, 5819ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 582f1ae32a1SGerd Hoffmann { 583f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2); 584f1ae32a1SGerd Hoffmann } 585f1ae32a1SGerd Hoffmann 586f1ae32a1SGerd Hoffmann static inline int ohci_read_td(OHCIState *ohci, 5879ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 588f1ae32a1SGerd Hoffmann { 589f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 590f1ae32a1SGerd Hoffmann } 591f1ae32a1SGerd Hoffmann 592f1ae32a1SGerd Hoffmann static inline int ohci_read_iso_td(OHCIState *ohci, 5939ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 594f1ae32a1SGerd Hoffmann { 595cf66ee8eSAlexey Kardashevskiy return get_dwords(ohci, addr, (uint32_t *)td, 4) || 596cf66ee8eSAlexey Kardashevskiy get_words(ohci, addr + 16, td->offset, 8); 597f1ae32a1SGerd Hoffmann } 598f1ae32a1SGerd Hoffmann 599f1ae32a1SGerd Hoffmann static inline int ohci_read_hcca(OHCIState *ohci, 6009ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 601f1ae32a1SGerd Hoffmann { 602cf66ee8eSAlexey Kardashevskiy return dma_memory_read(ohci->as, addr + ohci->localmem_base, 603cf66ee8eSAlexey Kardashevskiy hcca, sizeof(*hcca)); 604f1ae32a1SGerd Hoffmann } 605f1ae32a1SGerd Hoffmann 606f1ae32a1SGerd Hoffmann static inline int ohci_put_ed(OHCIState *ohci, 6079ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 608f1ae32a1SGerd Hoffmann { 60986e18caeSWei Yang /* ed->tail is under control of the HCD. 61086e18caeSWei Yang * Since just ed->head is changed by HC, just write back this 61186e18caeSWei Yang */ 61286e18caeSWei Yang 61386e18caeSWei Yang return put_dwords(ohci, addr + ED_WBACK_OFFSET, 61486e18caeSWei Yang (uint32_t *)((char *)ed + ED_WBACK_OFFSET), 61586e18caeSWei Yang ED_WBACK_SIZE >> 2); 616f1ae32a1SGerd Hoffmann } 617f1ae32a1SGerd Hoffmann 618f1ae32a1SGerd Hoffmann static inline int ohci_put_td(OHCIState *ohci, 6199ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 620f1ae32a1SGerd Hoffmann { 621f1ae32a1SGerd Hoffmann return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 622f1ae32a1SGerd Hoffmann } 623f1ae32a1SGerd Hoffmann 624f1ae32a1SGerd Hoffmann static inline int ohci_put_iso_td(OHCIState *ohci, 6259ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 626f1ae32a1SGerd Hoffmann { 627cae7f29cSJack Un return put_dwords(ohci, addr, (uint32_t *)td, 4) || 628cae7f29cSJack Un put_words(ohci, addr + 16, td->offset, 8); 629f1ae32a1SGerd Hoffmann } 630f1ae32a1SGerd Hoffmann 631f1ae32a1SGerd Hoffmann static inline int ohci_put_hcca(OHCIState *ohci, 6329ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 633f1ae32a1SGerd Hoffmann { 634cf66ee8eSAlexey Kardashevskiy return dma_memory_write(ohci->as, 6359ac6a217SDavid Gibson addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, 63686e18caeSWei Yang (char *)hcca + HCCA_WRITEBACK_OFFSET, 63786e18caeSWei Yang HCCA_WRITEBACK_SIZE); 638f1ae32a1SGerd Hoffmann } 639f1ae32a1SGerd Hoffmann 640f1ae32a1SGerd Hoffmann /* Read/Write the contents of a TD from/to main memory. */ 641cf66ee8eSAlexey Kardashevskiy static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, 6429ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 643f1ae32a1SGerd Hoffmann { 6449ac6a217SDavid Gibson dma_addr_t ptr, n; 645f1ae32a1SGerd Hoffmann 646f1ae32a1SGerd Hoffmann ptr = td->cbp; 647f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 648f1ae32a1SGerd Hoffmann if (n > len) 649f1ae32a1SGerd Hoffmann n = len; 650cf66ee8eSAlexey Kardashevskiy 651cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { 652cf66ee8eSAlexey Kardashevskiy return -1; 653cf66ee8eSAlexey Kardashevskiy } 654cf66ee8eSAlexey Kardashevskiy if (n == len) { 655cf66ee8eSAlexey Kardashevskiy return 0; 656cf66ee8eSAlexey Kardashevskiy } 657f1ae32a1SGerd Hoffmann ptr = td->be & ~0xfffu; 658f1ae32a1SGerd Hoffmann buf += n; 659cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 660cf66ee8eSAlexey Kardashevskiy len - n, dir)) { 661cf66ee8eSAlexey Kardashevskiy return -1; 662cf66ee8eSAlexey Kardashevskiy } 663cf66ee8eSAlexey Kardashevskiy return 0; 664f1ae32a1SGerd Hoffmann } 665f1ae32a1SGerd Hoffmann 666f1ae32a1SGerd Hoffmann /* Read/Write the contents of an ISO TD from/to main memory. */ 667cf66ee8eSAlexey Kardashevskiy static int ohci_copy_iso_td(OHCIState *ohci, 668f1ae32a1SGerd Hoffmann uint32_t start_addr, uint32_t end_addr, 6699ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 670f1ae32a1SGerd Hoffmann { 6719ac6a217SDavid Gibson dma_addr_t ptr, n; 672f1ae32a1SGerd Hoffmann 673f1ae32a1SGerd Hoffmann ptr = start_addr; 674f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 675f1ae32a1SGerd Hoffmann if (n > len) 676f1ae32a1SGerd Hoffmann n = len; 677cf66ee8eSAlexey Kardashevskiy 678cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { 679cf66ee8eSAlexey Kardashevskiy return -1; 680cf66ee8eSAlexey Kardashevskiy } 681cf66ee8eSAlexey Kardashevskiy if (n == len) { 682cf66ee8eSAlexey Kardashevskiy return 0; 683cf66ee8eSAlexey Kardashevskiy } 684f1ae32a1SGerd Hoffmann ptr = end_addr & ~0xfffu; 685f1ae32a1SGerd Hoffmann buf += n; 686cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 687cf66ee8eSAlexey Kardashevskiy len - n, dir)) { 688cf66ee8eSAlexey Kardashevskiy return -1; 689cf66ee8eSAlexey Kardashevskiy } 690cf66ee8eSAlexey Kardashevskiy return 0; 691f1ae32a1SGerd Hoffmann } 692f1ae32a1SGerd Hoffmann 693f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion); 694f1ae32a1SGerd Hoffmann 695f1ae32a1SGerd Hoffmann static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) 696f1ae32a1SGerd Hoffmann { 697f1ae32a1SGerd Hoffmann OHCIState *ohci = container_of(packet, OHCIState, usb_packet); 698dc1f5988SAlexey Kardashevskiy 699dc1f5988SAlexey Kardashevskiy trace_usb_ohci_async_complete(); 70069e25d26SAlexey Kardashevskiy ohci->async_complete = true; 701f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 1); 702f1ae32a1SGerd Hoffmann } 703f1ae32a1SGerd Hoffmann 704f1ae32a1SGerd Hoffmann #define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b))) 705f1ae32a1SGerd Hoffmann 706f1ae32a1SGerd Hoffmann static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, 707f1ae32a1SGerd Hoffmann int completion) 708f1ae32a1SGerd Hoffmann { 709f1ae32a1SGerd Hoffmann int dir; 710f1ae32a1SGerd Hoffmann size_t len = 0; 711f1ae32a1SGerd Hoffmann const char *str = NULL; 712f1ae32a1SGerd Hoffmann int pid; 713f1ae32a1SGerd Hoffmann int ret; 714f1ae32a1SGerd Hoffmann int i; 715f1ae32a1SGerd Hoffmann USBDevice *dev; 716f1ae32a1SGerd Hoffmann USBEndpoint *ep; 717f1ae32a1SGerd Hoffmann struct ohci_iso_td iso_td; 718f1ae32a1SGerd Hoffmann uint32_t addr; 719f1ae32a1SGerd Hoffmann uint16_t starting_frame; 720f1ae32a1SGerd Hoffmann int16_t relative_frame_number; 721f1ae32a1SGerd Hoffmann int frame_count; 722f1ae32a1SGerd Hoffmann uint32_t start_offset, next_offset, end_offset = 0; 723f1ae32a1SGerd Hoffmann uint32_t start_addr, end_addr; 724f1ae32a1SGerd Hoffmann 725f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 726f1ae32a1SGerd Hoffmann 727cf66ee8eSAlexey Kardashevskiy if (ohci_read_iso_td(ohci, addr, &iso_td)) { 728dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_read_failed(addr); 729cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 73026f670a2SLi Qiang return 1; 731f1ae32a1SGerd Hoffmann } 732f1ae32a1SGerd Hoffmann 733f1ae32a1SGerd Hoffmann starting_frame = OHCI_BM(iso_td.flags, TD_SF); 734f1ae32a1SGerd Hoffmann frame_count = OHCI_BM(iso_td.flags, TD_FC); 735f1ae32a1SGerd Hoffmann relative_frame_number = USUB(ohci->frame_number, starting_frame); 736f1ae32a1SGerd Hoffmann 737dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_head( 738f1ae32a1SGerd Hoffmann ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK, 739f1ae32a1SGerd Hoffmann iso_td.flags, iso_td.bp, iso_td.next, iso_td.be, 740f1ae32a1SGerd Hoffmann ohci->frame_number, starting_frame, 741bc0d104cSAlex Bennée frame_count, relative_frame_number); 7423af8f177SAlexey Kardashevskiy trace_usb_ohci_iso_td_head_offset( 7433af8f177SAlexey Kardashevskiy iso_td.offset[0], iso_td.offset[1], 7443af8f177SAlexey Kardashevskiy iso_td.offset[2], iso_td.offset[3], 7453af8f177SAlexey Kardashevskiy iso_td.offset[4], iso_td.offset[5], 7463af8f177SAlexey Kardashevskiy iso_td.offset[6], iso_td.offset[7]); 747f1ae32a1SGerd Hoffmann 748f1ae32a1SGerd Hoffmann if (relative_frame_number < 0) { 749dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number); 750f1ae32a1SGerd Hoffmann return 1; 751f1ae32a1SGerd Hoffmann } else if (relative_frame_number > frame_count) { 752f1ae32a1SGerd Hoffmann /* ISO TD expired - retire the TD to the Done Queue and continue with 753f1ae32a1SGerd Hoffmann the next ISO TD of the same ED */ 754dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number, 755f1ae32a1SGerd Hoffmann frame_count); 756f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 757f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 758f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 759f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 760f1ae32a1SGerd Hoffmann ohci->done = addr; 761f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 762f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 763f1ae32a1SGerd Hoffmann ohci->done_count = i; 764cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 765cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 766cf66ee8eSAlexey Kardashevskiy return 1; 767cf66ee8eSAlexey Kardashevskiy } 768f1ae32a1SGerd Hoffmann return 0; 769f1ae32a1SGerd Hoffmann } 770f1ae32a1SGerd Hoffmann 771f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 772f1ae32a1SGerd Hoffmann switch (dir) { 773f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 774f1ae32a1SGerd Hoffmann str = "in"; 775f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 776f1ae32a1SGerd Hoffmann break; 777f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 778f1ae32a1SGerd Hoffmann str = "out"; 779f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 780f1ae32a1SGerd Hoffmann break; 781f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 782f1ae32a1SGerd Hoffmann str = "setup"; 783f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 784f1ae32a1SGerd Hoffmann break; 785f1ae32a1SGerd Hoffmann default: 786dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_direction(dir); 787f1ae32a1SGerd Hoffmann return 1; 788f1ae32a1SGerd Hoffmann } 789f1ae32a1SGerd Hoffmann 790f1ae32a1SGerd Hoffmann if (!iso_td.bp || !iso_td.be) { 791dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be); 792f1ae32a1SGerd Hoffmann return 1; 793f1ae32a1SGerd Hoffmann } 794f1ae32a1SGerd Hoffmann 795f1ae32a1SGerd Hoffmann start_offset = iso_td.offset[relative_frame_number]; 796f1ae32a1SGerd Hoffmann next_offset = iso_td.offset[relative_frame_number + 1]; 797f1ae32a1SGerd Hoffmann 798f1ae32a1SGerd Hoffmann if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 799f1ae32a1SGerd Hoffmann ((relative_frame_number < frame_count) && 800f1ae32a1SGerd Hoffmann !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) { 801dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset); 802f1ae32a1SGerd Hoffmann return 1; 803f1ae32a1SGerd Hoffmann } 804f1ae32a1SGerd Hoffmann 805f1ae32a1SGerd Hoffmann if ((relative_frame_number < frame_count) && (start_offset > next_offset)) { 806dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset); 807f1ae32a1SGerd Hoffmann return 1; 808f1ae32a1SGerd Hoffmann } 809f1ae32a1SGerd Hoffmann 810f1ae32a1SGerd Hoffmann if ((start_offset & 0x1000) == 0) { 811f1ae32a1SGerd Hoffmann start_addr = (iso_td.bp & OHCI_PAGE_MASK) | 812f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 813f1ae32a1SGerd Hoffmann } else { 814f1ae32a1SGerd Hoffmann start_addr = (iso_td.be & OHCI_PAGE_MASK) | 815f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 816f1ae32a1SGerd Hoffmann } 817f1ae32a1SGerd Hoffmann 818f1ae32a1SGerd Hoffmann if (relative_frame_number < frame_count) { 819f1ae32a1SGerd Hoffmann end_offset = next_offset - 1; 820f1ae32a1SGerd Hoffmann if ((end_offset & 0x1000) == 0) { 821f1ae32a1SGerd Hoffmann end_addr = (iso_td.bp & OHCI_PAGE_MASK) | 822f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 823f1ae32a1SGerd Hoffmann } else { 824f1ae32a1SGerd Hoffmann end_addr = (iso_td.be & OHCI_PAGE_MASK) | 825f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 826f1ae32a1SGerd Hoffmann } 827f1ae32a1SGerd Hoffmann } else { 828f1ae32a1SGerd Hoffmann /* Last packet in the ISO TD */ 829f1ae32a1SGerd Hoffmann end_addr = iso_td.be; 830f1ae32a1SGerd Hoffmann } 831f1ae32a1SGerd Hoffmann 832f1ae32a1SGerd Hoffmann if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { 833f1ae32a1SGerd Hoffmann len = (end_addr & OHCI_OFFSET_MASK) + 0x1001 834f1ae32a1SGerd Hoffmann - (start_addr & OHCI_OFFSET_MASK); 835f1ae32a1SGerd Hoffmann } else { 836f1ae32a1SGerd Hoffmann len = end_addr - start_addr + 1; 837f1ae32a1SGerd Hoffmann } 838f1ae32a1SGerd Hoffmann 839f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 840cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 841cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 842cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 843cf66ee8eSAlexey Kardashevskiy return 1; 844cf66ee8eSAlexey Kardashevskiy } 845f1ae32a1SGerd Hoffmann } 846f1ae32a1SGerd Hoffmann 8479a77a0f5SHans de Goede if (!completion) { 848a6fb2ddbSHans de Goede bool int_req = relative_frame_number == frame_count && 849a6fb2ddbSHans de Goede OHCI_BM(iso_td.flags, TD_DI) == 0; 850f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 851f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 8528550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req); 853f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); 8549a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 8559a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 85636dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 857f1ae32a1SGerd Hoffmann return 1; 858f1ae32a1SGerd Hoffmann } 859f1ae32a1SGerd Hoffmann } 8609a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 8619a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 8629a77a0f5SHans de Goede } else { 8639a77a0f5SHans de Goede ret = ohci->usb_packet.status; 8649a77a0f5SHans de Goede } 865f1ae32a1SGerd Hoffmann 866dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr, 867dc1f5988SAlexey Kardashevskiy str, len, ret); 868f1ae32a1SGerd Hoffmann 869f1ae32a1SGerd Hoffmann /* Writeback */ 870f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) { 871f1ae32a1SGerd Hoffmann /* IN transfer succeeded */ 872cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 873cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 874cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 875cf66ee8eSAlexey Kardashevskiy return 1; 876cf66ee8eSAlexey Kardashevskiy } 877f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 878f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 879f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret); 880f1ae32a1SGerd Hoffmann } else if (dir == OHCI_TD_DIR_OUT && ret == len) { 881f1ae32a1SGerd Hoffmann /* OUT transfer succeeded */ 882f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 883f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 884f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); 885f1ae32a1SGerd Hoffmann } else { 886f1ae32a1SGerd Hoffmann if (ret > (ssize_t) len) { 887dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_overrun(ret, len); 888f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 889f1ae32a1SGerd Hoffmann OHCI_CC_DATAOVERRUN); 890f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 891f1ae32a1SGerd Hoffmann len); 892f1ae32a1SGerd Hoffmann } else if (ret >= 0) { 893dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_underrun(ret); 894f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 895f1ae32a1SGerd Hoffmann OHCI_CC_DATAUNDERRUN); 896f1ae32a1SGerd Hoffmann } else { 897f1ae32a1SGerd Hoffmann switch (ret) { 898f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 899f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 900f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 901f1ae32a1SGerd Hoffmann OHCI_CC_DEVICENOTRESPONDING); 902f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 903f1ae32a1SGerd Hoffmann 0); 904f1ae32a1SGerd Hoffmann break; 905f1ae32a1SGerd Hoffmann case USB_RET_NAK: 906f1ae32a1SGerd Hoffmann case USB_RET_STALL: 907dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_nak(ret); 908f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 909f1ae32a1SGerd Hoffmann OHCI_CC_STALL); 910f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 911f1ae32a1SGerd Hoffmann 0); 912f1ae32a1SGerd Hoffmann break; 913f1ae32a1SGerd Hoffmann default: 914dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_response(ret); 915f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 916f1ae32a1SGerd Hoffmann OHCI_CC_UNDEXPETEDPID); 917f1ae32a1SGerd Hoffmann break; 918f1ae32a1SGerd Hoffmann } 919f1ae32a1SGerd Hoffmann } 920f1ae32a1SGerd Hoffmann } 921f1ae32a1SGerd Hoffmann 922f1ae32a1SGerd Hoffmann if (relative_frame_number == frame_count) { 923f1ae32a1SGerd Hoffmann /* Last data packet of ISO TD - retire the TD to the Done Queue */ 924f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR); 925f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 926f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 927f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 928f1ae32a1SGerd Hoffmann ohci->done = addr; 929f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 930f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 931f1ae32a1SGerd Hoffmann ohci->done_count = i; 932f1ae32a1SGerd Hoffmann } 933cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 934cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 935cf66ee8eSAlexey Kardashevskiy } 936f1ae32a1SGerd Hoffmann return 1; 937f1ae32a1SGerd Hoffmann } 938f1ae32a1SGerd Hoffmann 939dc1f5988SAlexey Kardashevskiy static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) 940dc1f5988SAlexey Kardashevskiy { 941d87aa138SStefan Hajnoczi bool print16; 942d87aa138SStefan Hajnoczi bool printall; 943dc1f5988SAlexey Kardashevskiy const int width = 16; 944dc1f5988SAlexey Kardashevskiy int i; 945dc1f5988SAlexey Kardashevskiy char tmp[3 * width + 1]; 946dc1f5988SAlexey Kardashevskiy char *p = tmp; 947dc1f5988SAlexey Kardashevskiy 948d87aa138SStefan Hajnoczi print16 = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_SHORT); 949d87aa138SStefan Hajnoczi printall = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_FULL); 950d87aa138SStefan Hajnoczi 951dc1f5988SAlexey Kardashevskiy if (!printall && !print16) { 952dc1f5988SAlexey Kardashevskiy return; 953dc1f5988SAlexey Kardashevskiy } 954dc1f5988SAlexey Kardashevskiy 955dc1f5988SAlexey Kardashevskiy for (i = 0; ; i++) { 956dc1f5988SAlexey Kardashevskiy if (i && (!(i % width) || (i == len))) { 957dc1f5988SAlexey Kardashevskiy if (!printall) { 958dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_short(msg, tmp); 959dc1f5988SAlexey Kardashevskiy break; 960dc1f5988SAlexey Kardashevskiy } 961dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_full(msg, tmp); 962dc1f5988SAlexey Kardashevskiy p = tmp; 963dc1f5988SAlexey Kardashevskiy *p = 0; 964dc1f5988SAlexey Kardashevskiy } 965dc1f5988SAlexey Kardashevskiy if (i == len) { 966dc1f5988SAlexey Kardashevskiy break; 967dc1f5988SAlexey Kardashevskiy } 968dc1f5988SAlexey Kardashevskiy 969dc1f5988SAlexey Kardashevskiy p += sprintf(p, " %.2x", buf[i]); 970dc1f5988SAlexey Kardashevskiy } 971dc1f5988SAlexey Kardashevskiy } 972dc1f5988SAlexey Kardashevskiy 973f1ae32a1SGerd Hoffmann /* Service a transport descriptor. 974f1ae32a1SGerd Hoffmann Returns nonzero to terminate processing of this endpoint. */ 975f1ae32a1SGerd Hoffmann 976f1ae32a1SGerd Hoffmann static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) 977f1ae32a1SGerd Hoffmann { 978f1ae32a1SGerd Hoffmann int dir; 979f1ae32a1SGerd Hoffmann size_t len = 0, pktlen = 0; 980f1ae32a1SGerd Hoffmann const char *str = NULL; 981f1ae32a1SGerd Hoffmann int pid; 982f1ae32a1SGerd Hoffmann int ret; 983f1ae32a1SGerd Hoffmann int i; 984f1ae32a1SGerd Hoffmann USBDevice *dev; 985f1ae32a1SGerd Hoffmann USBEndpoint *ep; 986f1ae32a1SGerd Hoffmann struct ohci_td td; 987f1ae32a1SGerd Hoffmann uint32_t addr; 988f1ae32a1SGerd Hoffmann int flag_r; 989f1ae32a1SGerd Hoffmann int completion; 990f1ae32a1SGerd Hoffmann 991f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 992f1ae32a1SGerd Hoffmann /* See if this TD has already been submitted to the device. */ 993f1ae32a1SGerd Hoffmann completion = (addr == ohci->async_td); 994f1ae32a1SGerd Hoffmann if (completion && !ohci->async_complete) { 995dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_skip_async(); 996f1ae32a1SGerd Hoffmann return 1; 997f1ae32a1SGerd Hoffmann } 998cf66ee8eSAlexey Kardashevskiy if (ohci_read_td(ohci, addr, &td)) { 999dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_read_error(addr); 1000cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 10016ebc069dSLi Qiang return 1; 1002f1ae32a1SGerd Hoffmann } 1003f1ae32a1SGerd Hoffmann 1004f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 1005f1ae32a1SGerd Hoffmann switch (dir) { 1006f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 1007f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 1008f1ae32a1SGerd Hoffmann /* Same value. */ 1009f1ae32a1SGerd Hoffmann break; 1010f1ae32a1SGerd Hoffmann default: 1011f1ae32a1SGerd Hoffmann dir = OHCI_BM(td.flags, TD_DP); 1012f1ae32a1SGerd Hoffmann break; 1013f1ae32a1SGerd Hoffmann } 1014f1ae32a1SGerd Hoffmann 1015f1ae32a1SGerd Hoffmann switch (dir) { 1016f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 1017f1ae32a1SGerd Hoffmann str = "in"; 1018f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 1019f1ae32a1SGerd Hoffmann break; 1020f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 1021f1ae32a1SGerd Hoffmann str = "out"; 1022f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 1023f1ae32a1SGerd Hoffmann break; 1024f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 1025f1ae32a1SGerd Hoffmann str = "setup"; 1026f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 1027f1ae32a1SGerd Hoffmann break; 1028f1ae32a1SGerd Hoffmann default: 1029dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_direction(dir); 1030f1ae32a1SGerd Hoffmann return 1; 1031f1ae32a1SGerd Hoffmann } 1032f1ae32a1SGerd Hoffmann if (td.cbp && td.be) { 1033f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { 1034f1ae32a1SGerd Hoffmann len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); 1035f1ae32a1SGerd Hoffmann } else { 1036f1ae32a1SGerd Hoffmann len = (td.be - td.cbp) + 1; 1037f1ae32a1SGerd Hoffmann } 1038f1ae32a1SGerd Hoffmann 1039f1ae32a1SGerd Hoffmann pktlen = len; 1040f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 1041f1ae32a1SGerd Hoffmann /* The endpoint may not allow us to transfer it all now */ 1042f1ae32a1SGerd Hoffmann pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT; 1043f1ae32a1SGerd Hoffmann if (pktlen > len) { 1044f1ae32a1SGerd Hoffmann pktlen = len; 1045f1ae32a1SGerd Hoffmann } 1046f1ae32a1SGerd Hoffmann if (!completion) { 1047cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 1048cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 1049cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1050cf66ee8eSAlexey Kardashevskiy } 1051f1ae32a1SGerd Hoffmann } 1052f1ae32a1SGerd Hoffmann } 1053f1ae32a1SGerd Hoffmann } 1054f1ae32a1SGerd Hoffmann 1055f1ae32a1SGerd Hoffmann flag_r = (td.flags & OHCI_TD_R) != 0; 1056dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str, 1057dc1f5988SAlexey Kardashevskiy flag_r, td.cbp, td.be); 1058dc1f5988SAlexey Kardashevskiy ohci_td_pkt("OUT", ohci->usb_buf, pktlen); 1059f1ae32a1SGerd Hoffmann 1060f1ae32a1SGerd Hoffmann if (completion) { 1061f1ae32a1SGerd Hoffmann ohci->async_td = 0; 106269e25d26SAlexey Kardashevskiy ohci->async_complete = false; 1063f1ae32a1SGerd Hoffmann } else { 1064f1ae32a1SGerd Hoffmann if (ohci->async_td) { 1065f1ae32a1SGerd Hoffmann /* ??? The hardware should allow one active packet per 1066f1ae32a1SGerd Hoffmann endpoint. We only allow one active packet per controller. 1067f1ae32a1SGerd Hoffmann This should be sufficient as long as devices respond in a 1068f1ae32a1SGerd Hoffmann timely manner. 1069f1ae32a1SGerd Hoffmann */ 1070dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_too_many_pending(); 1071f1ae32a1SGerd Hoffmann return 1; 1072f1ae32a1SGerd Hoffmann } 1073f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 1074f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 10758550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r, 1076a6fb2ddbSHans de Goede OHCI_BM(td.flags, TD_DI) == 0); 1077f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); 10789a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 1079dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_packet_status(ohci->usb_packet.status); 1080dc1f5988SAlexey Kardashevskiy 10819a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 108236dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 1083f1ae32a1SGerd Hoffmann ohci->async_td = addr; 1084f1ae32a1SGerd Hoffmann return 1; 1085f1ae32a1SGerd Hoffmann } 1086f1ae32a1SGerd Hoffmann } 10879a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 10889a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 10899a77a0f5SHans de Goede } else { 10909a77a0f5SHans de Goede ret = ohci->usb_packet.status; 10919a77a0f5SHans de Goede } 10929a77a0f5SHans de Goede 1093f1ae32a1SGerd Hoffmann if (ret >= 0) { 1094f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN) { 1095cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1096cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 1097cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1098cf66ee8eSAlexey Kardashevskiy } 1099dc1f5988SAlexey Kardashevskiy ohci_td_pkt("IN", ohci->usb_buf, pktlen); 1100f1ae32a1SGerd Hoffmann } else { 1101f1ae32a1SGerd Hoffmann ret = pktlen; 1102f1ae32a1SGerd Hoffmann } 1103f1ae32a1SGerd Hoffmann } 1104f1ae32a1SGerd Hoffmann 1105f1ae32a1SGerd Hoffmann /* Writeback */ 1106f1ae32a1SGerd Hoffmann if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { 1107f1ae32a1SGerd Hoffmann /* Transmission succeeded. */ 1108f1ae32a1SGerd Hoffmann if (ret == len) { 1109f1ae32a1SGerd Hoffmann td.cbp = 0; 1110f1ae32a1SGerd Hoffmann } else { 1111f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfff) + ret > 0xfff) { 1112f1ae32a1SGerd Hoffmann td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff); 1113f1ae32a1SGerd Hoffmann } else { 1114f1ae32a1SGerd Hoffmann td.cbp += ret; 1115f1ae32a1SGerd Hoffmann } 1116f1ae32a1SGerd Hoffmann } 1117f1ae32a1SGerd Hoffmann td.flags |= OHCI_TD_T1; 1118f1ae32a1SGerd Hoffmann td.flags ^= OHCI_TD_T0; 1119f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); 1120f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 0); 1121f1ae32a1SGerd Hoffmann 1122f1ae32a1SGerd Hoffmann if ((dir != OHCI_TD_DIR_IN) && (ret != len)) { 1123f1ae32a1SGerd Hoffmann /* Partial packet transfer: TD not ready to retire yet */ 1124f1ae32a1SGerd Hoffmann goto exit_no_retire; 1125f1ae32a1SGerd Hoffmann } 1126f1ae32a1SGerd Hoffmann 1127f1ae32a1SGerd Hoffmann /* Setting ED_C is part of the TD retirement process */ 1128f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_ED_C; 1129f1ae32a1SGerd Hoffmann if (td.flags & OHCI_TD_T0) 1130f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_C; 1131f1ae32a1SGerd Hoffmann } else { 1132f1ae32a1SGerd Hoffmann if (ret >= 0) { 1133dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_underrun(); 1134f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); 1135f1ae32a1SGerd Hoffmann } else { 1136f1ae32a1SGerd Hoffmann switch (ret) { 1137f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 1138f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 1139dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_dev_error(); 1140f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); 11414b351a0fSJán Veselý break; 1142f1ae32a1SGerd Hoffmann case USB_RET_NAK: 1143dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_nak(); 1144f1ae32a1SGerd Hoffmann return 1; 1145f1ae32a1SGerd Hoffmann case USB_RET_STALL: 1146dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_stall(); 1147f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); 1148f1ae32a1SGerd Hoffmann break; 1149f1ae32a1SGerd Hoffmann case USB_RET_BABBLE: 1150dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_babble(); 1151f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 1152f1ae32a1SGerd Hoffmann break; 1153f1ae32a1SGerd Hoffmann default: 1154dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_device_response(ret); 1155f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); 1156f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 3); 1157f1ae32a1SGerd Hoffmann break; 1158f1ae32a1SGerd Hoffmann } 11597c48b95dSSebastian Bauer /* An error occured so we have to clear the interrupt counter. See 11607c48b95dSSebastian Bauer * spec at 6.4.4 on page 104 */ 11617c48b95dSSebastian Bauer ohci->done_count = 0; 1162f1ae32a1SGerd Hoffmann } 1163f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_H; 1164f1ae32a1SGerd Hoffmann } 1165f1ae32a1SGerd Hoffmann 1166f1ae32a1SGerd Hoffmann /* Retire this TD */ 1167f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 1168f1ae32a1SGerd Hoffmann ed->head |= td.next & OHCI_DPTR_MASK; 1169f1ae32a1SGerd Hoffmann td.next = ohci->done; 1170f1ae32a1SGerd Hoffmann ohci->done = addr; 1171f1ae32a1SGerd Hoffmann i = OHCI_BM(td.flags, TD_DI); 1172f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 1173f1ae32a1SGerd Hoffmann ohci->done_count = i; 1174f1ae32a1SGerd Hoffmann exit_no_retire: 1175cf66ee8eSAlexey Kardashevskiy if (ohci_put_td(ohci, addr, &td)) { 1176cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1177cf66ee8eSAlexey Kardashevskiy return 1; 1178cf66ee8eSAlexey Kardashevskiy } 1179f1ae32a1SGerd Hoffmann return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; 1180f1ae32a1SGerd Hoffmann } 1181f1ae32a1SGerd Hoffmann 1182f1ae32a1SGerd Hoffmann /* Service an endpoint list. Returns nonzero if active TD were found. */ 1183f1ae32a1SGerd Hoffmann static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) 1184f1ae32a1SGerd Hoffmann { 1185f1ae32a1SGerd Hoffmann struct ohci_ed ed; 1186f1ae32a1SGerd Hoffmann uint32_t next_ed; 1187f1ae32a1SGerd Hoffmann uint32_t cur; 1188f1ae32a1SGerd Hoffmann int active; 118995ed5693SLi Qiang uint32_t link_cnt = 0; 1190f1ae32a1SGerd Hoffmann active = 0; 1191f1ae32a1SGerd Hoffmann 1192f1ae32a1SGerd Hoffmann if (head == 0) 1193f1ae32a1SGerd Hoffmann return 0; 1194f1ae32a1SGerd Hoffmann 1195f1ae32a1SGerd Hoffmann for (cur = head; cur; cur = next_ed) { 1196cf66ee8eSAlexey Kardashevskiy if (ohci_read_ed(ohci, cur, &ed)) { 1197dc1f5988SAlexey Kardashevskiy trace_usb_ohci_ed_read_error(cur); 1198cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1199f1ae32a1SGerd Hoffmann return 0; 1200f1ae32a1SGerd Hoffmann } 1201f1ae32a1SGerd Hoffmann 1202f1ae32a1SGerd Hoffmann next_ed = ed.next & OHCI_DPTR_MASK; 1203f1ae32a1SGerd Hoffmann 120495ed5693SLi Qiang if (++link_cnt > ED_LINK_LIMIT) { 120595ed5693SLi Qiang ohci_die(ohci); 120695ed5693SLi Qiang return 0; 120795ed5693SLi Qiang } 120895ed5693SLi Qiang 1209f1ae32a1SGerd Hoffmann if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) { 1210f1ae32a1SGerd Hoffmann uint32_t addr; 1211f1ae32a1SGerd Hoffmann /* Cancel pending packets for ED that have been paused. */ 1212f1ae32a1SGerd Hoffmann addr = ed.head & OHCI_DPTR_MASK; 1213f1ae32a1SGerd Hoffmann if (ohci->async_td && addr == ohci->async_td) { 1214f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1215f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1216f79738b0SHans de Goede usb_device_ep_stopped(ohci->usb_packet.ep->dev, 1217f79738b0SHans de Goede ohci->usb_packet.ep); 1218f1ae32a1SGerd Hoffmann } 1219f1ae32a1SGerd Hoffmann continue; 1220f1ae32a1SGerd Hoffmann } 1221f1ae32a1SGerd Hoffmann 1222f1ae32a1SGerd Hoffmann while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { 12233af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0, 12243af8f177SAlexey Kardashevskiy (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, 12253af8f177SAlexey Kardashevskiy ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); 12263af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt_flags( 1227f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), 1228f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, 1229f1ae32a1SGerd Hoffmann (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, 12303af8f177SAlexey Kardashevskiy OHCI_BM(ed.flags, ED_MPS)); 1231dc1f5988SAlexey Kardashevskiy 1232f1ae32a1SGerd Hoffmann active = 1; 1233f1ae32a1SGerd Hoffmann 1234f1ae32a1SGerd Hoffmann if ((ed.flags & OHCI_ED_F) == 0) { 1235f1ae32a1SGerd Hoffmann if (ohci_service_td(ohci, &ed)) 1236f1ae32a1SGerd Hoffmann break; 1237f1ae32a1SGerd Hoffmann } else { 1238f1ae32a1SGerd Hoffmann /* Handle isochronous endpoints */ 1239f1ae32a1SGerd Hoffmann if (ohci_service_iso_td(ohci, &ed, completion)) 1240f1ae32a1SGerd Hoffmann break; 1241f1ae32a1SGerd Hoffmann } 1242f1ae32a1SGerd Hoffmann } 1243f1ae32a1SGerd Hoffmann 1244cf66ee8eSAlexey Kardashevskiy if (ohci_put_ed(ohci, cur, &ed)) { 1245cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1246cf66ee8eSAlexey Kardashevskiy return 0; 1247cf66ee8eSAlexey Kardashevskiy } 1248f1ae32a1SGerd Hoffmann } 1249f1ae32a1SGerd Hoffmann 1250f1ae32a1SGerd Hoffmann return active; 1251f1ae32a1SGerd Hoffmann } 1252f1ae32a1SGerd Hoffmann 1253fd0a10cdSLaurent Vivier /* set a timer for EOF */ 1254fd0a10cdSLaurent Vivier static void ohci_eof_timer(OHCIState *ohci) 1255f1ae32a1SGerd Hoffmann { 1256bc72ad67SAlex Bligh timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time); 1257fd0a10cdSLaurent Vivier } 1258fd0a10cdSLaurent Vivier /* Set a timer for EOF and generate a SOF event */ 1259fd0a10cdSLaurent Vivier static void ohci_sof(OHCIState *ohci) 1260fd0a10cdSLaurent Vivier { 1261*a60f39a4SMiguel GAIO ohci->sof_time += usb_frame_time; 1262fd0a10cdSLaurent Vivier ohci_eof_timer(ohci); 1263f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_SF); 1264f1ae32a1SGerd Hoffmann } 1265f1ae32a1SGerd Hoffmann 1266f1ae32a1SGerd Hoffmann /* Process Control and Bulk lists. */ 1267f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion) 1268f1ae32a1SGerd Hoffmann { 1269f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { 1270f1ae32a1SGerd Hoffmann if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) { 1271dc1f5988SAlexey Kardashevskiy trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur); 1272f1ae32a1SGerd Hoffmann } 1273f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) { 1274f1ae32a1SGerd Hoffmann ohci->ctrl_cur = 0; 1275f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_CLF; 1276f1ae32a1SGerd Hoffmann } 1277f1ae32a1SGerd Hoffmann } 1278f1ae32a1SGerd Hoffmann 1279f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { 1280f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) { 1281f1ae32a1SGerd Hoffmann ohci->bulk_cur = 0; 1282f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_BLF; 1283f1ae32a1SGerd Hoffmann } 1284f1ae32a1SGerd Hoffmann } 1285f1ae32a1SGerd Hoffmann } 1286f1ae32a1SGerd Hoffmann 1287f1ae32a1SGerd Hoffmann /* Do frame processing on frame boundary */ 1288f1ae32a1SGerd Hoffmann static void ohci_frame_boundary(void *opaque) 1289f1ae32a1SGerd Hoffmann { 1290f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1291f1ae32a1SGerd Hoffmann struct ohci_hcca hcca; 1292f1ae32a1SGerd Hoffmann 1293cf66ee8eSAlexey Kardashevskiy if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) { 1294dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hcca_read_error(ohci->hcca); 1295cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1296cf66ee8eSAlexey Kardashevskiy return; 1297cf66ee8eSAlexey Kardashevskiy } 1298f1ae32a1SGerd Hoffmann 1299f1ae32a1SGerd Hoffmann /* Process all the lists at the end of the frame */ 1300f1ae32a1SGerd Hoffmann if (ohci->ctl & OHCI_CTL_PLE) { 1301f1ae32a1SGerd Hoffmann int n; 1302f1ae32a1SGerd Hoffmann 1303f1ae32a1SGerd Hoffmann n = ohci->frame_number & 0x1f; 1304f1ae32a1SGerd Hoffmann ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0); 1305f1ae32a1SGerd Hoffmann } 1306f1ae32a1SGerd Hoffmann 1307f1ae32a1SGerd Hoffmann /* Cancel all pending packets if either of the lists has been disabled. */ 1308f79738b0SHans de Goede if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { 1309f79738b0SHans de Goede if (ohci->async_td) { 1310f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1311f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1312f1ae32a1SGerd Hoffmann } 1313f79738b0SHans de Goede ohci_stop_endpoints(ohci); 1314f79738b0SHans de Goede } 1315f1ae32a1SGerd Hoffmann ohci->old_ctl = ohci->ctl; 1316f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 0); 1317f1ae32a1SGerd Hoffmann 1318cf66ee8eSAlexey Kardashevskiy /* Stop if UnrecoverableError happened or ohci_sof will crash */ 1319cf66ee8eSAlexey Kardashevskiy if (ohci->intr_status & OHCI_INTR_UE) { 1320cf66ee8eSAlexey Kardashevskiy return; 1321cf66ee8eSAlexey Kardashevskiy } 1322cf66ee8eSAlexey Kardashevskiy 1323f1ae32a1SGerd Hoffmann /* Frame boundary, so do EOF stuf here */ 1324f1ae32a1SGerd Hoffmann ohci->frt = ohci->fit; 1325f1ae32a1SGerd Hoffmann 1326f1ae32a1SGerd Hoffmann /* Increment frame number and take care of endianness. */ 1327f1ae32a1SGerd Hoffmann ohci->frame_number = (ohci->frame_number + 1) & 0xffff; 1328f1ae32a1SGerd Hoffmann hcca.frame = cpu_to_le16(ohci->frame_number); 1329f1ae32a1SGerd Hoffmann 1330f1ae32a1SGerd Hoffmann if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { 1331f1ae32a1SGerd Hoffmann if (!ohci->done) 1332f1ae32a1SGerd Hoffmann abort(); 1333f1ae32a1SGerd Hoffmann if (ohci->intr & ohci->intr_status) 1334f1ae32a1SGerd Hoffmann ohci->done |= 1; 1335f1ae32a1SGerd Hoffmann hcca.done = cpu_to_le32(ohci->done); 1336f1ae32a1SGerd Hoffmann ohci->done = 0; 1337f1ae32a1SGerd Hoffmann ohci->done_count = 7; 1338f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_WD); 1339f1ae32a1SGerd Hoffmann } 1340f1ae32a1SGerd Hoffmann 1341f1ae32a1SGerd Hoffmann if (ohci->done_count != 7 && ohci->done_count != 0) 1342f1ae32a1SGerd Hoffmann ohci->done_count--; 1343f1ae32a1SGerd Hoffmann 1344f1ae32a1SGerd Hoffmann /* Do SOF stuff here */ 1345f1ae32a1SGerd Hoffmann ohci_sof(ohci); 1346f1ae32a1SGerd Hoffmann 1347f1ae32a1SGerd Hoffmann /* Writeback HCCA */ 1348cf66ee8eSAlexey Kardashevskiy if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) { 1349cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1350cf66ee8eSAlexey Kardashevskiy } 1351f1ae32a1SGerd Hoffmann } 1352f1ae32a1SGerd Hoffmann 1353f1ae32a1SGerd Hoffmann /* Start sending SOF tokens across the USB bus, lists are processed in 1354f1ae32a1SGerd Hoffmann * next frame 1355f1ae32a1SGerd Hoffmann */ 1356f1ae32a1SGerd Hoffmann static int ohci_bus_start(OHCIState *ohci) 1357f1ae32a1SGerd Hoffmann { 1358dc1f5988SAlexey Kardashevskiy trace_usb_ohci_start(ohci->name); 1359f1ae32a1SGerd Hoffmann 1360fd0a10cdSLaurent Vivier /* Delay the first SOF event by one frame time as 1361fd0a10cdSLaurent Vivier * linux driver is not ready to receive it and 1362fd0a10cdSLaurent Vivier * can meet some race conditions 1363fd0a10cdSLaurent Vivier */ 1364fd0a10cdSLaurent Vivier 1365*a60f39a4SMiguel GAIO ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1366fd0a10cdSLaurent Vivier ohci_eof_timer(ohci); 1367f1ae32a1SGerd Hoffmann 1368f1ae32a1SGerd Hoffmann return 1; 1369f1ae32a1SGerd Hoffmann } 1370f1ae32a1SGerd Hoffmann 1371f1ae32a1SGerd Hoffmann /* Stop sending SOF tokens on the bus */ 1372f1ae32a1SGerd Hoffmann static void ohci_bus_stop(OHCIState *ohci) 1373f1ae32a1SGerd Hoffmann { 1374dc1f5988SAlexey Kardashevskiy trace_usb_ohci_stop(ohci->name); 1375bc72ad67SAlex Bligh timer_del(ohci->eof_timer); 1376f1ae32a1SGerd Hoffmann } 1377f1ae32a1SGerd Hoffmann 1378f1ae32a1SGerd Hoffmann /* Sets a flag in a port status register but only set it if the port is 1379f1ae32a1SGerd Hoffmann * connected, if not set ConnectStatusChange flag. If flag is enabled 1380f1ae32a1SGerd Hoffmann * return 1. 1381f1ae32a1SGerd Hoffmann */ 1382f1ae32a1SGerd Hoffmann static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) 1383f1ae32a1SGerd Hoffmann { 1384f1ae32a1SGerd Hoffmann int ret = 1; 1385f1ae32a1SGerd Hoffmann 1386f1ae32a1SGerd Hoffmann /* writing a 0 has no effect */ 1387f1ae32a1SGerd Hoffmann if (val == 0) 1388f1ae32a1SGerd Hoffmann return 0; 1389f1ae32a1SGerd Hoffmann 1390f1ae32a1SGerd Hoffmann /* If CurrentConnectStatus is cleared we set 1391f1ae32a1SGerd Hoffmann * ConnectStatusChange 1392f1ae32a1SGerd Hoffmann */ 1393f1ae32a1SGerd Hoffmann if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { 1394f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_CSC; 1395f1ae32a1SGerd Hoffmann if (ohci->rhstatus & OHCI_RHS_DRWE) { 1396f1ae32a1SGerd Hoffmann /* TODO: CSC is a wakeup event */ 1397f1ae32a1SGerd Hoffmann } 1398f1ae32a1SGerd Hoffmann return 0; 1399f1ae32a1SGerd Hoffmann } 1400f1ae32a1SGerd Hoffmann 1401f1ae32a1SGerd Hoffmann if (ohci->rhport[i].ctrl & val) 1402f1ae32a1SGerd Hoffmann ret = 0; 1403f1ae32a1SGerd Hoffmann 1404f1ae32a1SGerd Hoffmann /* set the bit */ 1405f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= val; 1406f1ae32a1SGerd Hoffmann 1407f1ae32a1SGerd Hoffmann return ret; 1408f1ae32a1SGerd Hoffmann } 1409f1ae32a1SGerd Hoffmann 1410f1ae32a1SGerd Hoffmann /* Set the frame interval - frame interval toggle is manipulated by the hcd only */ 1411f1ae32a1SGerd Hoffmann static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) 1412f1ae32a1SGerd Hoffmann { 1413f1ae32a1SGerd Hoffmann val &= OHCI_FMI_FI; 1414f1ae32a1SGerd Hoffmann 1415f1ae32a1SGerd Hoffmann if (val != ohci->fi) { 1416dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi); 1417f1ae32a1SGerd Hoffmann } 1418f1ae32a1SGerd Hoffmann 1419f1ae32a1SGerd Hoffmann ohci->fi = val; 1420f1ae32a1SGerd Hoffmann } 1421f1ae32a1SGerd Hoffmann 1422f1ae32a1SGerd Hoffmann static void ohci_port_power(OHCIState *ohci, int i, int p) 1423f1ae32a1SGerd Hoffmann { 1424f1ae32a1SGerd Hoffmann if (p) { 1425f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_PPS; 1426f1ae32a1SGerd Hoffmann } else { 1427f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| 1428f1ae32a1SGerd Hoffmann OHCI_PORT_CCS| 1429f1ae32a1SGerd Hoffmann OHCI_PORT_PSS| 1430f1ae32a1SGerd Hoffmann OHCI_PORT_PRS); 1431f1ae32a1SGerd Hoffmann } 1432f1ae32a1SGerd Hoffmann } 1433f1ae32a1SGerd Hoffmann 1434f1ae32a1SGerd Hoffmann /* Set HcControlRegister */ 1435f1ae32a1SGerd Hoffmann static void ohci_set_ctl(OHCIState *ohci, uint32_t val) 1436f1ae32a1SGerd Hoffmann { 1437f1ae32a1SGerd Hoffmann uint32_t old_state; 1438f1ae32a1SGerd Hoffmann uint32_t new_state; 1439f1ae32a1SGerd Hoffmann 1440f1ae32a1SGerd Hoffmann old_state = ohci->ctl & OHCI_CTL_HCFS; 1441f1ae32a1SGerd Hoffmann ohci->ctl = val; 1442f1ae32a1SGerd Hoffmann new_state = ohci->ctl & OHCI_CTL_HCFS; 1443f1ae32a1SGerd Hoffmann 1444f1ae32a1SGerd Hoffmann /* no state change */ 1445f1ae32a1SGerd Hoffmann if (old_state == new_state) 1446f1ae32a1SGerd Hoffmann return; 1447f1ae32a1SGerd Hoffmann 1448dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_ctl(ohci->name, new_state); 1449f1ae32a1SGerd Hoffmann switch (new_state) { 1450f1ae32a1SGerd Hoffmann case OHCI_USB_OPERATIONAL: 1451f1ae32a1SGerd Hoffmann ohci_bus_start(ohci); 1452f1ae32a1SGerd Hoffmann break; 1453f1ae32a1SGerd Hoffmann case OHCI_USB_SUSPEND: 1454f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 1455087462c7SLaurent Vivier /* clear pending SF otherwise linux driver loops in ohci_irq() */ 1456087462c7SLaurent Vivier ohci->intr_status &= ~OHCI_INTR_SF; 1457087462c7SLaurent Vivier ohci_intr_update(ohci); 1458f1ae32a1SGerd Hoffmann break; 1459f1ae32a1SGerd Hoffmann case OHCI_USB_RESUME: 1460dc1f5988SAlexey Kardashevskiy trace_usb_ohci_resume(ohci->name); 1461f1ae32a1SGerd Hoffmann break; 1462f1ae32a1SGerd Hoffmann case OHCI_USB_RESET: 14637d938fd1SHervé Poussineau ohci_roothub_reset(ohci); 1464f1ae32a1SGerd Hoffmann break; 1465f1ae32a1SGerd Hoffmann } 1466f1ae32a1SGerd Hoffmann } 1467f1ae32a1SGerd Hoffmann 1468f1ae32a1SGerd Hoffmann static uint32_t ohci_get_frame_remaining(OHCIState *ohci) 1469f1ae32a1SGerd Hoffmann { 1470f1ae32a1SGerd Hoffmann uint16_t fr; 1471f1ae32a1SGerd Hoffmann int64_t tks; 1472f1ae32a1SGerd Hoffmann 1473f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) 1474f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1475f1ae32a1SGerd Hoffmann 1476f1ae32a1SGerd Hoffmann /* Being in USB operational state guarnatees sof_time was 1477f1ae32a1SGerd Hoffmann * set already. 1478f1ae32a1SGerd Hoffmann */ 1479bc72ad67SAlex Bligh tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time; 1480*a60f39a4SMiguel GAIO if (tks < 0) { 1481*a60f39a4SMiguel GAIO tks = 0; 1482*a60f39a4SMiguel GAIO } 1483f1ae32a1SGerd Hoffmann 1484f1ae32a1SGerd Hoffmann /* avoid muldiv if possible */ 1485f1ae32a1SGerd Hoffmann if (tks >= usb_frame_time) 1486f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1487f1ae32a1SGerd Hoffmann 1488cd1f16f9SLaurent Vivier tks = tks / usb_bit_time; 1489f1ae32a1SGerd Hoffmann fr = (uint16_t)(ohci->fi - tks); 1490f1ae32a1SGerd Hoffmann 1491f1ae32a1SGerd Hoffmann return (ohci->frt << 31) | fr; 1492f1ae32a1SGerd Hoffmann } 1493f1ae32a1SGerd Hoffmann 1494f1ae32a1SGerd Hoffmann 1495f1ae32a1SGerd Hoffmann /* Set root hub status */ 1496f1ae32a1SGerd Hoffmann static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) 1497f1ae32a1SGerd Hoffmann { 1498f1ae32a1SGerd Hoffmann uint32_t old_state; 1499f1ae32a1SGerd Hoffmann 1500f1ae32a1SGerd Hoffmann old_state = ohci->rhstatus; 1501f1ae32a1SGerd Hoffmann 1502f1ae32a1SGerd Hoffmann /* write 1 to clear OCIC */ 1503f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_OCIC) 1504f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_OCIC; 1505f1ae32a1SGerd Hoffmann 1506f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPS) { 1507f1ae32a1SGerd Hoffmann int i; 1508f1ae32a1SGerd Hoffmann 1509f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1510f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 0); 1511dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_down(); 1512f1ae32a1SGerd Hoffmann } 1513f1ae32a1SGerd Hoffmann 1514f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPSC) { 1515f1ae32a1SGerd Hoffmann int i; 1516f1ae32a1SGerd Hoffmann 1517f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1518f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 1); 1519dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_up(); 1520f1ae32a1SGerd Hoffmann } 1521f1ae32a1SGerd Hoffmann 1522f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_DRWE) 1523f1ae32a1SGerd Hoffmann ohci->rhstatus |= OHCI_RHS_DRWE; 1524f1ae32a1SGerd Hoffmann 1525f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_CRWE) 1526f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_DRWE; 1527f1ae32a1SGerd Hoffmann 1528f1ae32a1SGerd Hoffmann if (old_state != ohci->rhstatus) 1529f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1530f1ae32a1SGerd Hoffmann } 1531f1ae32a1SGerd Hoffmann 1532f1ae32a1SGerd Hoffmann /* Set root hub port status */ 1533f1ae32a1SGerd Hoffmann static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) 1534f1ae32a1SGerd Hoffmann { 1535f1ae32a1SGerd Hoffmann uint32_t old_state; 1536f1ae32a1SGerd Hoffmann OHCIPort *port; 1537f1ae32a1SGerd Hoffmann 1538f1ae32a1SGerd Hoffmann port = &ohci->rhport[portnum]; 1539f1ae32a1SGerd Hoffmann old_state = port->ctrl; 1540f1ae32a1SGerd Hoffmann 1541f1ae32a1SGerd Hoffmann /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ 1542f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_WTC) 1543f1ae32a1SGerd Hoffmann port->ctrl &= ~(val & OHCI_PORT_WTC); 1544f1ae32a1SGerd Hoffmann 1545f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_CCS) 1546f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 1547f1ae32a1SGerd Hoffmann 1548f1ae32a1SGerd Hoffmann ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); 1549f1ae32a1SGerd Hoffmann 1550f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) { 1551dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_suspend(portnum); 1552f1ae32a1SGerd Hoffmann } 1553f1ae32a1SGerd Hoffmann 1554f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { 1555dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_reset(portnum); 1556f1ae32a1SGerd Hoffmann usb_device_reset(port->port.dev); 1557f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PRS; 1558f1ae32a1SGerd Hoffmann /* ??? Should this also set OHCI_PORT_PESC. */ 1559f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; 1560f1ae32a1SGerd Hoffmann } 1561f1ae32a1SGerd Hoffmann 1562f1ae32a1SGerd Hoffmann /* Invert order here to ensure in ambiguous case, device is 1563f1ae32a1SGerd Hoffmann * powered up... 1564f1ae32a1SGerd Hoffmann */ 1565f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_LSDA) 1566f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 0); 1567f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_PPS) 1568f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 1); 1569f1ae32a1SGerd Hoffmann 1570f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) 1571f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1572f1ae32a1SGerd Hoffmann } 1573f1ae32a1SGerd Hoffmann 1574f1ae32a1SGerd Hoffmann static uint64_t ohci_mem_read(void *opaque, 1575a8170e5eSAvi Kivity hwaddr addr, 1576f1ae32a1SGerd Hoffmann unsigned size) 1577f1ae32a1SGerd Hoffmann { 1578f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1579f1ae32a1SGerd Hoffmann uint32_t retval; 1580f1ae32a1SGerd Hoffmann 1581f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1582f1ae32a1SGerd Hoffmann if (addr & 3) { 1583dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_unaligned(addr); 1584f1ae32a1SGerd Hoffmann return 0xffffffff; 1585f1ae32a1SGerd Hoffmann } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1586f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1587f1ae32a1SGerd Hoffmann retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; 1588f1ae32a1SGerd Hoffmann } else { 1589f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1590f1ae32a1SGerd Hoffmann case 0: /* HcRevision */ 1591f1ae32a1SGerd Hoffmann retval = 0x10; 1592f1ae32a1SGerd Hoffmann break; 1593f1ae32a1SGerd Hoffmann 1594f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1595f1ae32a1SGerd Hoffmann retval = ohci->ctl; 1596f1ae32a1SGerd Hoffmann break; 1597f1ae32a1SGerd Hoffmann 1598f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1599f1ae32a1SGerd Hoffmann retval = ohci->status; 1600f1ae32a1SGerd Hoffmann break; 1601f1ae32a1SGerd Hoffmann 1602f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1603f1ae32a1SGerd Hoffmann retval = ohci->intr_status; 1604f1ae32a1SGerd Hoffmann break; 1605f1ae32a1SGerd Hoffmann 1606f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1607f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1608f1ae32a1SGerd Hoffmann retval = ohci->intr; 1609f1ae32a1SGerd Hoffmann break; 1610f1ae32a1SGerd Hoffmann 1611f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1612f1ae32a1SGerd Hoffmann retval = ohci->hcca; 1613f1ae32a1SGerd Hoffmann break; 1614f1ae32a1SGerd Hoffmann 1615f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1616f1ae32a1SGerd Hoffmann retval = ohci->per_cur; 1617f1ae32a1SGerd Hoffmann break; 1618f1ae32a1SGerd Hoffmann 1619f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1620f1ae32a1SGerd Hoffmann retval = ohci->ctrl_head; 1621f1ae32a1SGerd Hoffmann break; 1622f1ae32a1SGerd Hoffmann 1623f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1624f1ae32a1SGerd Hoffmann retval = ohci->ctrl_cur; 1625f1ae32a1SGerd Hoffmann break; 1626f1ae32a1SGerd Hoffmann 1627f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1628f1ae32a1SGerd Hoffmann retval = ohci->bulk_head; 1629f1ae32a1SGerd Hoffmann break; 1630f1ae32a1SGerd Hoffmann 1631f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1632f1ae32a1SGerd Hoffmann retval = ohci->bulk_cur; 1633f1ae32a1SGerd Hoffmann break; 1634f1ae32a1SGerd Hoffmann 1635f1ae32a1SGerd Hoffmann case 12: /* HcDoneHead */ 1636f1ae32a1SGerd Hoffmann retval = ohci->done; 1637f1ae32a1SGerd Hoffmann break; 1638f1ae32a1SGerd Hoffmann 1639f1ae32a1SGerd Hoffmann case 13: /* HcFmInterretval */ 1640f1ae32a1SGerd Hoffmann retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); 1641f1ae32a1SGerd Hoffmann break; 1642f1ae32a1SGerd Hoffmann 1643f1ae32a1SGerd Hoffmann case 14: /* HcFmRemaining */ 1644f1ae32a1SGerd Hoffmann retval = ohci_get_frame_remaining(ohci); 1645f1ae32a1SGerd Hoffmann break; 1646f1ae32a1SGerd Hoffmann 1647f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1648f1ae32a1SGerd Hoffmann retval = ohci->frame_number; 1649f1ae32a1SGerd Hoffmann break; 1650f1ae32a1SGerd Hoffmann 1651f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1652f1ae32a1SGerd Hoffmann retval = ohci->pstart; 1653f1ae32a1SGerd Hoffmann break; 1654f1ae32a1SGerd Hoffmann 1655f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1656f1ae32a1SGerd Hoffmann retval = ohci->lst; 1657f1ae32a1SGerd Hoffmann break; 1658f1ae32a1SGerd Hoffmann 1659f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1660f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_a; 1661f1ae32a1SGerd Hoffmann break; 1662f1ae32a1SGerd Hoffmann 1663f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1664f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_b; 1665f1ae32a1SGerd Hoffmann break; 1666f1ae32a1SGerd Hoffmann 1667f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1668f1ae32a1SGerd Hoffmann retval = ohci->rhstatus; 1669f1ae32a1SGerd Hoffmann break; 1670f1ae32a1SGerd Hoffmann 1671f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1672f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1673f1ae32a1SGerd Hoffmann retval = ohci->hstatus & ohci->hmask; 1674f1ae32a1SGerd Hoffmann break; 1675f1ae32a1SGerd Hoffmann 1676f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1677f1ae32a1SGerd Hoffmann retval = ohci->hreset; 1678f1ae32a1SGerd Hoffmann break; 1679f1ae32a1SGerd Hoffmann 1680f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1681f1ae32a1SGerd Hoffmann retval = ohci->hmask; 1682f1ae32a1SGerd Hoffmann break; 1683f1ae32a1SGerd Hoffmann 1684f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1685f1ae32a1SGerd Hoffmann retval = ohci->htest; 1686f1ae32a1SGerd Hoffmann break; 1687f1ae32a1SGerd Hoffmann 1688f1ae32a1SGerd Hoffmann default: 1689dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_bad_offset(addr); 1690f1ae32a1SGerd Hoffmann retval = 0xffffffff; 1691f1ae32a1SGerd Hoffmann } 1692f1ae32a1SGerd Hoffmann } 1693f1ae32a1SGerd Hoffmann 1694f1ae32a1SGerd Hoffmann return retval; 1695f1ae32a1SGerd Hoffmann } 1696f1ae32a1SGerd Hoffmann 1697f1ae32a1SGerd Hoffmann static void ohci_mem_write(void *opaque, 1698a8170e5eSAvi Kivity hwaddr addr, 1699f1ae32a1SGerd Hoffmann uint64_t val, 1700f1ae32a1SGerd Hoffmann unsigned size) 1701f1ae32a1SGerd Hoffmann { 1702f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1703f1ae32a1SGerd Hoffmann 1704f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1705f1ae32a1SGerd Hoffmann if (addr & 3) { 1706dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_unaligned(addr); 1707f1ae32a1SGerd Hoffmann return; 1708f1ae32a1SGerd Hoffmann } 1709f1ae32a1SGerd Hoffmann 1710f1ae32a1SGerd Hoffmann if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1711f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1712f1ae32a1SGerd Hoffmann ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); 1713f1ae32a1SGerd Hoffmann return; 1714f1ae32a1SGerd Hoffmann } 1715f1ae32a1SGerd Hoffmann 1716f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1717f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1718f1ae32a1SGerd Hoffmann ohci_set_ctl(ohci, val); 1719f1ae32a1SGerd Hoffmann break; 1720f1ae32a1SGerd Hoffmann 1721f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1722f1ae32a1SGerd Hoffmann /* SOC is read-only */ 1723f1ae32a1SGerd Hoffmann val = (val & ~OHCI_STATUS_SOC); 1724f1ae32a1SGerd Hoffmann 1725f1ae32a1SGerd Hoffmann /* Bits written as '0' remain unchanged in the register */ 1726f1ae32a1SGerd Hoffmann ohci->status |= val; 1727f1ae32a1SGerd Hoffmann 1728f1ae32a1SGerd Hoffmann if (ohci->status & OHCI_STATUS_HCR) 17290922c3f6SHervé Poussineau ohci_soft_reset(ohci); 1730f1ae32a1SGerd Hoffmann break; 1731f1ae32a1SGerd Hoffmann 1732f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1733f1ae32a1SGerd Hoffmann ohci->intr_status &= ~val; 1734f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1735f1ae32a1SGerd Hoffmann break; 1736f1ae32a1SGerd Hoffmann 1737f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1738f1ae32a1SGerd Hoffmann ohci->intr |= val; 1739f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1740f1ae32a1SGerd Hoffmann break; 1741f1ae32a1SGerd Hoffmann 1742f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1743f1ae32a1SGerd Hoffmann ohci->intr &= ~val; 1744f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1745f1ae32a1SGerd Hoffmann break; 1746f1ae32a1SGerd Hoffmann 1747f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1748f1ae32a1SGerd Hoffmann ohci->hcca = val & OHCI_HCCA_MASK; 1749f1ae32a1SGerd Hoffmann break; 1750f1ae32a1SGerd Hoffmann 1751f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1752f1ae32a1SGerd Hoffmann /* Ignore writes to this read-only register, Linux does them */ 1753f1ae32a1SGerd Hoffmann break; 1754f1ae32a1SGerd Hoffmann 1755f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1756f1ae32a1SGerd Hoffmann ohci->ctrl_head = val & OHCI_EDPTR_MASK; 1757f1ae32a1SGerd Hoffmann break; 1758f1ae32a1SGerd Hoffmann 1759f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1760f1ae32a1SGerd Hoffmann ohci->ctrl_cur = val & OHCI_EDPTR_MASK; 1761f1ae32a1SGerd Hoffmann break; 1762f1ae32a1SGerd Hoffmann 1763f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1764f1ae32a1SGerd Hoffmann ohci->bulk_head = val & OHCI_EDPTR_MASK; 1765f1ae32a1SGerd Hoffmann break; 1766f1ae32a1SGerd Hoffmann 1767f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1768f1ae32a1SGerd Hoffmann ohci->bulk_cur = val & OHCI_EDPTR_MASK; 1769f1ae32a1SGerd Hoffmann break; 1770f1ae32a1SGerd Hoffmann 1771f1ae32a1SGerd Hoffmann case 13: /* HcFmInterval */ 1772f1ae32a1SGerd Hoffmann ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; 1773f1ae32a1SGerd Hoffmann ohci->fit = (val & OHCI_FMI_FIT) >> 31; 1774f1ae32a1SGerd Hoffmann ohci_set_frame_interval(ohci, val); 1775f1ae32a1SGerd Hoffmann break; 1776f1ae32a1SGerd Hoffmann 1777f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1778f1ae32a1SGerd Hoffmann break; 1779f1ae32a1SGerd Hoffmann 1780f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1781f1ae32a1SGerd Hoffmann ohci->pstart = val & 0xffff; 1782f1ae32a1SGerd Hoffmann break; 1783f1ae32a1SGerd Hoffmann 1784f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1785f1ae32a1SGerd Hoffmann ohci->lst = val & 0xffff; 1786f1ae32a1SGerd Hoffmann break; 1787f1ae32a1SGerd Hoffmann 1788f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1789f1ae32a1SGerd Hoffmann ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; 1790f1ae32a1SGerd Hoffmann ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; 1791f1ae32a1SGerd Hoffmann break; 1792f1ae32a1SGerd Hoffmann 1793f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1794f1ae32a1SGerd Hoffmann break; 1795f1ae32a1SGerd Hoffmann 1796f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1797f1ae32a1SGerd Hoffmann ohci_set_hub_status(ohci, val); 1798f1ae32a1SGerd Hoffmann break; 1799f1ae32a1SGerd Hoffmann 1800f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1801f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1802f1ae32a1SGerd Hoffmann ohci->hstatus &= ~(val & ohci->hmask); 18037fa96d73SGerd Hoffmann break; 1804f1ae32a1SGerd Hoffmann 1805f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1806f1ae32a1SGerd Hoffmann ohci->hreset = val & ~OHCI_HRESET_FSBIR; 1807f1ae32a1SGerd Hoffmann if (val & OHCI_HRESET_FSBIR) 180884d04e21SHervé Poussineau ohci_hard_reset(ohci); 1809f1ae32a1SGerd Hoffmann break; 1810f1ae32a1SGerd Hoffmann 1811f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1812f1ae32a1SGerd Hoffmann ohci->hmask = val; 1813f1ae32a1SGerd Hoffmann break; 1814f1ae32a1SGerd Hoffmann 1815f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1816f1ae32a1SGerd Hoffmann ohci->htest = val; 1817f1ae32a1SGerd Hoffmann break; 1818f1ae32a1SGerd Hoffmann 1819f1ae32a1SGerd Hoffmann default: 1820dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_bad_offset(addr); 1821f1ae32a1SGerd Hoffmann break; 1822f1ae32a1SGerd Hoffmann } 1823f1ae32a1SGerd Hoffmann } 1824f1ae32a1SGerd Hoffmann 1825f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev) 1826f1ae32a1SGerd Hoffmann { 1827f1ae32a1SGerd Hoffmann if (ohci->async_td && 1828f1ae32a1SGerd Hoffmann usb_packet_is_inflight(&ohci->usb_packet) && 1829f1ae32a1SGerd Hoffmann ohci->usb_packet.ep->dev == dev) { 1830f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1831f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1832f1ae32a1SGerd Hoffmann } 1833f1ae32a1SGerd Hoffmann } 1834f1ae32a1SGerd Hoffmann 1835f1ae32a1SGerd Hoffmann static const MemoryRegionOps ohci_mem_ops = { 1836f1ae32a1SGerd Hoffmann .read = ohci_mem_read, 1837f1ae32a1SGerd Hoffmann .write = ohci_mem_write, 1838f1ae32a1SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 1839f1ae32a1SGerd Hoffmann }; 1840f1ae32a1SGerd Hoffmann 1841f1ae32a1SGerd Hoffmann static USBPortOps ohci_port_ops = { 1842f1ae32a1SGerd Hoffmann .attach = ohci_attach, 1843f1ae32a1SGerd Hoffmann .detach = ohci_detach, 1844f1ae32a1SGerd Hoffmann .child_detach = ohci_child_detach, 1845f1ae32a1SGerd Hoffmann .wakeup = ohci_wakeup, 1846f1ae32a1SGerd Hoffmann .complete = ohci_async_complete_packet, 1847f1ae32a1SGerd Hoffmann }; 1848f1ae32a1SGerd Hoffmann 1849f1ae32a1SGerd Hoffmann static USBBusOps ohci_bus_ops = { 1850f1ae32a1SGerd Hoffmann }; 1851f1ae32a1SGerd Hoffmann 185287581feaSMarkus Armbruster static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, 18539ac6a217SDavid Gibson int num_ports, dma_addr_t localmem_base, 18549ac6a217SDavid Gibson char *masterbus, uint32_t firstport, 185587581feaSMarkus Armbruster AddressSpace *as, Error **errp) 1856f1ae32a1SGerd Hoffmann { 1857f4bbaaf5SMarkus Armbruster Error *err = NULL; 1858f1ae32a1SGerd Hoffmann int i; 1859f1ae32a1SGerd Hoffmann 1860df32fd1cSPaolo Bonzini ohci->as = as; 18619ac6a217SDavid Gibson 1862d400fc01SThomas Huth if (num_ports > OHCI_MAX_PORTS) { 1863d400fc01SThomas Huth error_setg(errp, "OHCI num-ports=%d is too big (limit is %d ports)", 1864d400fc01SThomas Huth num_ports, OHCI_MAX_PORTS); 1865d400fc01SThomas Huth return; 1866d400fc01SThomas Huth } 1867d400fc01SThomas Huth 1868f1ae32a1SGerd Hoffmann if (usb_frame_time == 0) { 1869f1ae32a1SGerd Hoffmann #ifdef OHCI_TIME_WARP 187073bcb24dSRutuja Shah usb_frame_time = NANOSECONDS_PER_SECOND; 187173bcb24dSRutuja Shah usb_bit_time = NANOSECONDS_PER_SECOND / (USB_HZ / 1000); 1872f1ae32a1SGerd Hoffmann #else 187373bcb24dSRutuja Shah usb_frame_time = NANOSECONDS_PER_SECOND / 1000; 187473bcb24dSRutuja Shah if (NANOSECONDS_PER_SECOND >= USB_HZ) { 187573bcb24dSRutuja Shah usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ; 1876f1ae32a1SGerd Hoffmann } else { 1877f1ae32a1SGerd Hoffmann usb_bit_time = 1; 1878f1ae32a1SGerd Hoffmann } 1879f1ae32a1SGerd Hoffmann #endif 1880dc1f5988SAlexey Kardashevskiy trace_usb_ohci_init_time(usb_frame_time, usb_bit_time); 1881f1ae32a1SGerd Hoffmann } 1882f1ae32a1SGerd Hoffmann 1883f1ae32a1SGerd Hoffmann ohci->num_ports = num_ports; 1884f1ae32a1SGerd Hoffmann if (masterbus) { 1885f1ae32a1SGerd Hoffmann USBPort *ports[OHCI_MAX_PORTS]; 1886f1ae32a1SGerd Hoffmann for(i = 0; i < num_ports; i++) { 1887f1ae32a1SGerd Hoffmann ports[i] = &ohci->rhport[i].port; 1888f1ae32a1SGerd Hoffmann } 1889f4bbaaf5SMarkus Armbruster usb_register_companion(masterbus, ports, num_ports, 1890f1ae32a1SGerd Hoffmann firstport, ohci, &ohci_port_ops, 1891f4bbaaf5SMarkus Armbruster USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, 1892f4bbaaf5SMarkus Armbruster &err); 1893f4bbaaf5SMarkus Armbruster if (err) { 189487581feaSMarkus Armbruster error_propagate(errp, err); 189587581feaSMarkus Armbruster return; 1896f1ae32a1SGerd Hoffmann } 1897f1ae32a1SGerd Hoffmann } else { 1898c889b3a5SAndreas Färber usb_bus_new(&ohci->bus, sizeof(ohci->bus), &ohci_bus_ops, dev); 1899f1ae32a1SGerd Hoffmann for (i = 0; i < num_ports; i++) { 1900f1ae32a1SGerd Hoffmann usb_register_port(&ohci->bus, &ohci->rhport[i].port, 1901f1ae32a1SGerd Hoffmann ohci, i, &ohci_port_ops, 1902f1ae32a1SGerd Hoffmann USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); 1903f1ae32a1SGerd Hoffmann } 1904f1ae32a1SGerd Hoffmann } 1905f1ae32a1SGerd Hoffmann 190622fc860bSPaolo Bonzini memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops, 190722fc860bSPaolo Bonzini ohci, "ohci", 256); 1908f1ae32a1SGerd Hoffmann ohci->localmem_base = localmem_base; 1909f1ae32a1SGerd Hoffmann 1910f1ae32a1SGerd Hoffmann ohci->name = object_get_typename(OBJECT(dev)); 1911f1ae32a1SGerd Hoffmann usb_packet_init(&ohci->usb_packet); 1912f1ae32a1SGerd Hoffmann 1913f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1914fa1298c2SGerd Hoffmann 1915fa1298c2SGerd Hoffmann ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1916fa1298c2SGerd Hoffmann ohci_frame_boundary, ohci); 1917f1ae32a1SGerd Hoffmann } 1918f1ae32a1SGerd Hoffmann 19191aa0c0c7SHu Tao #define TYPE_PCI_OHCI "pci-ohci" 19201aa0c0c7SHu Tao #define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) 19211aa0c0c7SHu Tao 1922f1ae32a1SGerd Hoffmann typedef struct { 19231aa0c0c7SHu Tao /*< private >*/ 19241aa0c0c7SHu Tao PCIDevice parent_obj; 19251aa0c0c7SHu Tao /*< public >*/ 19261aa0c0c7SHu Tao 1927f1ae32a1SGerd Hoffmann OHCIState state; 1928f1ae32a1SGerd Hoffmann char *masterbus; 1929f1ae32a1SGerd Hoffmann uint32_t num_ports; 1930f1ae32a1SGerd Hoffmann uint32_t firstport; 1931f1ae32a1SGerd Hoffmann } OHCIPCIState; 1932f1ae32a1SGerd Hoffmann 1933cf66ee8eSAlexey Kardashevskiy /** A typical O/EHCI will stop operating, set itself into error state 1934cf66ee8eSAlexey Kardashevskiy * (which can be queried by MMIO) and will set PERR in its config 1935cf66ee8eSAlexey Kardashevskiy * space to signal that it got an error 1936cf66ee8eSAlexey Kardashevskiy */ 1937cf66ee8eSAlexey Kardashevskiy static void ohci_die(OHCIState *ohci) 1938cf66ee8eSAlexey Kardashevskiy { 1939cf66ee8eSAlexey Kardashevskiy OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); 1940cf66ee8eSAlexey Kardashevskiy 1941dc1f5988SAlexey Kardashevskiy trace_usb_ohci_die(); 1942cf66ee8eSAlexey Kardashevskiy 1943cf66ee8eSAlexey Kardashevskiy ohci_set_interrupt(ohci, OHCI_INTR_UE); 1944cf66ee8eSAlexey Kardashevskiy ohci_bus_stop(ohci); 1945cf66ee8eSAlexey Kardashevskiy pci_set_word(dev->parent_obj.config + PCI_STATUS, 1946cf66ee8eSAlexey Kardashevskiy PCI_STATUS_DETECTED_PARITY); 1947cf66ee8eSAlexey Kardashevskiy } 1948cf66ee8eSAlexey Kardashevskiy 194987581feaSMarkus Armbruster static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp) 1950f1ae32a1SGerd Hoffmann { 195187581feaSMarkus Armbruster Error *err = NULL; 19521aa0c0c7SHu Tao OHCIPCIState *ohci = PCI_OHCI(dev); 1953f1ae32a1SGerd Hoffmann 19541aa0c0c7SHu Tao dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ 19551aa0c0c7SHu Tao dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ 1956f1ae32a1SGerd Hoffmann 195787581feaSMarkus Armbruster usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, 19589ac6a217SDavid Gibson ohci->masterbus, ohci->firstport, 195987581feaSMarkus Armbruster pci_get_address_space(dev), &err); 196087581feaSMarkus Armbruster if (err) { 196187581feaSMarkus Armbruster error_propagate(errp, err); 196287581feaSMarkus Armbruster return; 1963f1ae32a1SGerd Hoffmann } 1964f1ae32a1SGerd Hoffmann 196587581feaSMarkus Armbruster ohci->state.irq = pci_allocate_irq(dev); 19661aa0c0c7SHu Tao pci_register_bar(dev, 0, 0, &ohci->state.mem); 1967f1ae32a1SGerd Hoffmann } 1968f1ae32a1SGerd Hoffmann 196907832c38SGonglei static void usb_ohci_exit(PCIDevice *dev) 197007832c38SGonglei { 197107832c38SGonglei OHCIPCIState *ohci = PCI_OHCI(dev); 197207832c38SGonglei OHCIState *s = &ohci->state; 197307832c38SGonglei 1974dc1f5988SAlexey Kardashevskiy trace_usb_ohci_exit(s->name); 197507832c38SGonglei ohci_bus_stop(s); 197607832c38SGonglei 197707832c38SGonglei if (s->async_td) { 197807832c38SGonglei usb_cancel_packet(&s->usb_packet); 197907832c38SGonglei s->async_td = 0; 198007832c38SGonglei } 198107832c38SGonglei ohci_stop_endpoints(s); 198207832c38SGonglei 198307832c38SGonglei if (!ohci->masterbus) { 198407832c38SGonglei usb_bus_release(&s->bus); 198507832c38SGonglei } 1986fa1298c2SGerd Hoffmann 1987fa1298c2SGerd Hoffmann timer_del(s->eof_timer); 1988fa1298c2SGerd Hoffmann timer_free(s->eof_timer); 198907832c38SGonglei } 199007832c38SGonglei 199188dd1b8dSGonglei static void usb_ohci_reset_pci(DeviceState *d) 199288dd1b8dSGonglei { 199388dd1b8dSGonglei PCIDevice *dev = PCI_DEVICE(d); 199488dd1b8dSGonglei OHCIPCIState *ohci = PCI_OHCI(dev); 199588dd1b8dSGonglei OHCIState *s = &ohci->state; 199688dd1b8dSGonglei 199784d04e21SHervé Poussineau ohci_hard_reset(s); 199888dd1b8dSGonglei } 199988dd1b8dSGonglei 20001aa0c0c7SHu Tao #define TYPE_SYSBUS_OHCI "sysbus-ohci" 20011aa0c0c7SHu Tao #define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI) 20021aa0c0c7SHu Tao 2003f1ae32a1SGerd Hoffmann typedef struct { 20041aa0c0c7SHu Tao /*< private >*/ 20051aa0c0c7SHu Tao SysBusDevice parent_obj; 20061aa0c0c7SHu Tao /*< public >*/ 20071aa0c0c7SHu Tao 2008f1ae32a1SGerd Hoffmann OHCIState ohci; 2009d7145b66SBALATON Zoltan char *masterbus; 2010f1ae32a1SGerd Hoffmann uint32_t num_ports; 2011d7145b66SBALATON Zoltan uint32_t firstport; 20129ac6a217SDavid Gibson dma_addr_t dma_offset; 2013f1ae32a1SGerd Hoffmann } OHCISysBusState; 2014f1ae32a1SGerd Hoffmann 2015457215ecSHu Tao static void ohci_realize_pxa(DeviceState *dev, Error **errp) 2016f1ae32a1SGerd Hoffmann { 20171aa0c0c7SHu Tao OHCISysBusState *s = SYSBUS_OHCI(dev); 2018457215ecSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 2019d7145b66SBALATON Zoltan Error *err = NULL; 2020f1ae32a1SGerd Hoffmann 2021d7145b66SBALATON Zoltan usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, 2022d7145b66SBALATON Zoltan s->masterbus, s->firstport, 2023d7145b66SBALATON Zoltan &address_space_memory, &err); 2024d7145b66SBALATON Zoltan if (err) { 2025d7145b66SBALATON Zoltan error_propagate(errp, err); 2026d7145b66SBALATON Zoltan return; 2027d7145b66SBALATON Zoltan } 2028457215ecSHu Tao sysbus_init_irq(sbd, &s->ohci.irq); 2029457215ecSHu Tao sysbus_init_mmio(sbd, &s->ohci.mem); 2030f1ae32a1SGerd Hoffmann } 2031f1ae32a1SGerd Hoffmann 203288dd1b8dSGonglei static void usb_ohci_reset_sysbus(DeviceState *dev) 203388dd1b8dSGonglei { 203488dd1b8dSGonglei OHCISysBusState *s = SYSBUS_OHCI(dev); 203588dd1b8dSGonglei OHCIState *ohci = &s->ohci; 203688dd1b8dSGonglei 203784d04e21SHervé Poussineau ohci_hard_reset(ohci); 203888dd1b8dSGonglei } 203988dd1b8dSGonglei 2040f1ae32a1SGerd Hoffmann static Property ohci_pci_properties[] = { 2041f1ae32a1SGerd Hoffmann DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), 2042f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), 2043f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), 2044f1ae32a1SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 2045f1ae32a1SGerd Hoffmann }; 2046f1ae32a1SGerd Hoffmann 204769e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_state_port = { 204869e25d26SAlexey Kardashevskiy .name = "ohci-core/port", 204969e25d26SAlexey Kardashevskiy .version_id = 1, 205069e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 205169e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 205269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl, OHCIPort), 205369e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 205469e25d26SAlexey Kardashevskiy }, 205569e25d26SAlexey Kardashevskiy }; 205669e25d26SAlexey Kardashevskiy 205769e25d26SAlexey Kardashevskiy static bool ohci_eof_timer_needed(void *opaque) 205869e25d26SAlexey Kardashevskiy { 205969e25d26SAlexey Kardashevskiy OHCIState *ohci = opaque; 206069e25d26SAlexey Kardashevskiy 2061fa1298c2SGerd Hoffmann return timer_pending(ohci->eof_timer); 206269e25d26SAlexey Kardashevskiy } 206369e25d26SAlexey Kardashevskiy 206469e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_eof_timer = { 206569e25d26SAlexey Kardashevskiy .name = "ohci-core/eof-timer", 206669e25d26SAlexey Kardashevskiy .version_id = 1, 206769e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 20685cd8cadaSJuan Quintela .needed = ohci_eof_timer_needed, 206969e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 2070e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(eof_timer, OHCIState), 207169e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 207269e25d26SAlexey Kardashevskiy }, 207369e25d26SAlexey Kardashevskiy }; 207469e25d26SAlexey Kardashevskiy 2075b9b45b4aSStefan Weil static const VMStateDescription vmstate_ohci_state = { 207669e25d26SAlexey Kardashevskiy .name = "ohci-core", 207769e25d26SAlexey Kardashevskiy .version_id = 1, 207869e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 207969e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 208069e25d26SAlexey Kardashevskiy VMSTATE_INT64(sof_time, OHCIState), 208169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctl, OHCIState), 208269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(status, OHCIState), 208369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr_status, OHCIState), 208469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr, OHCIState), 208569e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hcca, OHCIState), 208669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_head, OHCIState), 208769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_cur, OHCIState), 208869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_head, OHCIState), 208969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_cur, OHCIState), 209069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(per_cur, OHCIState), 209169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(done, OHCIState), 209269e25d26SAlexey Kardashevskiy VMSTATE_INT32(done_count, OHCIState), 209369e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fsmps, OHCIState), 209469e25d26SAlexey Kardashevskiy VMSTATE_UINT8(fit, OHCIState), 209569e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fi, OHCIState), 209669e25d26SAlexey Kardashevskiy VMSTATE_UINT8(frt, OHCIState), 209769e25d26SAlexey Kardashevskiy VMSTATE_UINT16(frame_number, OHCIState), 209869e25d26SAlexey Kardashevskiy VMSTATE_UINT16(padding, OHCIState), 209969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(pstart, OHCIState), 210069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(lst, OHCIState), 210169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_a, OHCIState), 210269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_b, OHCIState), 210369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhstatus, OHCIState), 210469e25d26SAlexey Kardashevskiy VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0, 210569e25d26SAlexey Kardashevskiy vmstate_ohci_state_port, OHCIPort), 210669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hstatus, OHCIState), 210769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hmask, OHCIState), 210869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hreset, OHCIState), 210969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(htest, OHCIState), 211069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(old_ctl, OHCIState), 211169e25d26SAlexey Kardashevskiy VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192), 211269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(async_td, OHCIState), 211369e25d26SAlexey Kardashevskiy VMSTATE_BOOL(async_complete, OHCIState), 211469e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 211569e25d26SAlexey Kardashevskiy }, 21165cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 21175cd8cadaSJuan Quintela &vmstate_ohci_eof_timer, 21185cd8cadaSJuan Quintela NULL 211969e25d26SAlexey Kardashevskiy } 212069e25d26SAlexey Kardashevskiy }; 212169e25d26SAlexey Kardashevskiy 212269e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci = { 212369e25d26SAlexey Kardashevskiy .name = "ohci", 212469e25d26SAlexey Kardashevskiy .version_id = 1, 212569e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 212669e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 212769e25d26SAlexey Kardashevskiy VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), 212869e25d26SAlexey Kardashevskiy VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState), 212969e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 213069e25d26SAlexey Kardashevskiy } 213169e25d26SAlexey Kardashevskiy }; 213269e25d26SAlexey Kardashevskiy 2133f1ae32a1SGerd Hoffmann static void ohci_pci_class_init(ObjectClass *klass, void *data) 2134f1ae32a1SGerd Hoffmann { 2135f1ae32a1SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 2136f1ae32a1SGerd Hoffmann PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 2137f1ae32a1SGerd Hoffmann 213887581feaSMarkus Armbruster k->realize = usb_ohci_realize_pci; 213907832c38SGonglei k->exit = usb_ohci_exit; 2140f1ae32a1SGerd Hoffmann k->vendor_id = PCI_VENDOR_ID_APPLE; 2141f1ae32a1SGerd Hoffmann k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; 2142f1ae32a1SGerd Hoffmann k->class_id = PCI_CLASS_SERIAL_USB; 2143125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_USB, dc->categories); 2144f1ae32a1SGerd Hoffmann dc->desc = "Apple USB Controller"; 2145f1ae32a1SGerd Hoffmann dc->props = ohci_pci_properties; 21462897ae02SIgor Mammedov dc->hotpluggable = false; 214769e25d26SAlexey Kardashevskiy dc->vmsd = &vmstate_ohci; 214888dd1b8dSGonglei dc->reset = usb_ohci_reset_pci; 2149f1ae32a1SGerd Hoffmann } 2150f1ae32a1SGerd Hoffmann 21518c43a6f0SAndreas Färber static const TypeInfo ohci_pci_info = { 21521aa0c0c7SHu Tao .name = TYPE_PCI_OHCI, 2153f1ae32a1SGerd Hoffmann .parent = TYPE_PCI_DEVICE, 2154f1ae32a1SGerd Hoffmann .instance_size = sizeof(OHCIPCIState), 2155f1ae32a1SGerd Hoffmann .class_init = ohci_pci_class_init, 2156fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) { 2157fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 2158fd3b02c8SEduardo Habkost { }, 2159fd3b02c8SEduardo Habkost }, 2160f1ae32a1SGerd Hoffmann }; 2161f1ae32a1SGerd Hoffmann 2162f1ae32a1SGerd Hoffmann static Property ohci_sysbus_properties[] = { 2163d7145b66SBALATON Zoltan DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus), 2164f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), 2165d7145b66SBALATON Zoltan DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0), 21666998b6c7SVijay Kumar B DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0), 2167f1ae32a1SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 2168f1ae32a1SGerd Hoffmann }; 2169f1ae32a1SGerd Hoffmann 2170f1ae32a1SGerd Hoffmann static void ohci_sysbus_class_init(ObjectClass *klass, void *data) 2171f1ae32a1SGerd Hoffmann { 2172f1ae32a1SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 2173f1ae32a1SGerd Hoffmann 2174457215ecSHu Tao dc->realize = ohci_realize_pxa; 2175125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_USB, dc->categories); 2176f1ae32a1SGerd Hoffmann dc->desc = "OHCI USB Controller"; 2177f1ae32a1SGerd Hoffmann dc->props = ohci_sysbus_properties; 217888dd1b8dSGonglei dc->reset = usb_ohci_reset_sysbus; 2179f1ae32a1SGerd Hoffmann } 2180f1ae32a1SGerd Hoffmann 21818c43a6f0SAndreas Färber static const TypeInfo ohci_sysbus_info = { 21821aa0c0c7SHu Tao .name = TYPE_SYSBUS_OHCI, 2183f1ae32a1SGerd Hoffmann .parent = TYPE_SYS_BUS_DEVICE, 2184f1ae32a1SGerd Hoffmann .instance_size = sizeof(OHCISysBusState), 2185f1ae32a1SGerd Hoffmann .class_init = ohci_sysbus_class_init, 2186f1ae32a1SGerd Hoffmann }; 2187f1ae32a1SGerd Hoffmann 2188f1ae32a1SGerd Hoffmann static void ohci_register_types(void) 2189f1ae32a1SGerd Hoffmann { 2190f1ae32a1SGerd Hoffmann type_register_static(&ohci_pci_info); 2191f1ae32a1SGerd Hoffmann type_register_static(&ohci_sysbus_info); 2192f1ae32a1SGerd Hoffmann } 2193f1ae32a1SGerd Hoffmann 2194f1ae32a1SGerd Hoffmann type_init(ohci_register_types) 2195