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 28f1ae32a1SGerd Hoffmann #include "hw/hw.h" 291de7afc9SPaolo Bonzini #include "qemu/timer.h" 30f1ae32a1SGerd Hoffmann #include "hw/usb.h" 31a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h" 32f1ae32a1SGerd Hoffmann #include "hw/sysbus.h" 339ac6a217SDavid Gibson #include "hw/qdev-dma.h" 34dc1f5988SAlexey Kardashevskiy #include "trace.h" 35f1ae32a1SGerd Hoffmann 36f1ae32a1SGerd Hoffmann /* This causes frames to occur 1000x slower */ 37f1ae32a1SGerd Hoffmann //#define OHCI_TIME_WARP 1 38f1ae32a1SGerd Hoffmann 39f1ae32a1SGerd Hoffmann /* Number of Downstream Ports on the root hub. */ 40f1ae32a1SGerd Hoffmann 41f1ae32a1SGerd Hoffmann #define OHCI_MAX_PORTS 15 42f1ae32a1SGerd Hoffmann 43f1ae32a1SGerd Hoffmann static int64_t usb_frame_time; 44f1ae32a1SGerd Hoffmann static int64_t usb_bit_time; 45f1ae32a1SGerd Hoffmann 46f1ae32a1SGerd Hoffmann typedef struct OHCIPort { 47f1ae32a1SGerd Hoffmann USBPort port; 48f1ae32a1SGerd Hoffmann uint32_t ctrl; 49f1ae32a1SGerd Hoffmann } OHCIPort; 50f1ae32a1SGerd Hoffmann 51f1ae32a1SGerd Hoffmann typedef struct { 52f1ae32a1SGerd Hoffmann USBBus bus; 53f1ae32a1SGerd Hoffmann qemu_irq irq; 54f1ae32a1SGerd Hoffmann MemoryRegion mem; 55df32fd1cSPaolo Bonzini AddressSpace *as; 56f1ae32a1SGerd Hoffmann int num_ports; 57f1ae32a1SGerd Hoffmann const char *name; 58f1ae32a1SGerd Hoffmann 59f1ae32a1SGerd Hoffmann QEMUTimer *eof_timer; 60f1ae32a1SGerd Hoffmann int64_t sof_time; 61f1ae32a1SGerd Hoffmann 62f1ae32a1SGerd Hoffmann /* OHCI state */ 63f1ae32a1SGerd Hoffmann /* Control partition */ 64f1ae32a1SGerd Hoffmann uint32_t ctl, status; 65f1ae32a1SGerd Hoffmann uint32_t intr_status; 66f1ae32a1SGerd Hoffmann uint32_t intr; 67f1ae32a1SGerd Hoffmann 68f1ae32a1SGerd Hoffmann /* memory pointer partition */ 69f1ae32a1SGerd Hoffmann uint32_t hcca; 70f1ae32a1SGerd Hoffmann uint32_t ctrl_head, ctrl_cur; 71f1ae32a1SGerd Hoffmann uint32_t bulk_head, bulk_cur; 72f1ae32a1SGerd Hoffmann uint32_t per_cur; 73f1ae32a1SGerd Hoffmann uint32_t done; 7469e25d26SAlexey Kardashevskiy int32_t done_count; 75f1ae32a1SGerd Hoffmann 76f1ae32a1SGerd Hoffmann /* Frame counter partition */ 7769e25d26SAlexey Kardashevskiy uint16_t fsmps; 7869e25d26SAlexey Kardashevskiy uint8_t fit; 7969e25d26SAlexey Kardashevskiy uint16_t fi; 8069e25d26SAlexey Kardashevskiy uint8_t frt; 81f1ae32a1SGerd Hoffmann uint16_t frame_number; 82f1ae32a1SGerd Hoffmann uint16_t padding; 83f1ae32a1SGerd Hoffmann uint32_t pstart; 84f1ae32a1SGerd Hoffmann uint32_t lst; 85f1ae32a1SGerd Hoffmann 86f1ae32a1SGerd Hoffmann /* Root Hub partition */ 87f1ae32a1SGerd Hoffmann uint32_t rhdesc_a, rhdesc_b; 88f1ae32a1SGerd Hoffmann uint32_t rhstatus; 89f1ae32a1SGerd Hoffmann OHCIPort rhport[OHCI_MAX_PORTS]; 90f1ae32a1SGerd Hoffmann 91f1ae32a1SGerd Hoffmann /* PXA27x Non-OHCI events */ 92f1ae32a1SGerd Hoffmann uint32_t hstatus; 93f1ae32a1SGerd Hoffmann uint32_t hmask; 94f1ae32a1SGerd Hoffmann uint32_t hreset; 95f1ae32a1SGerd Hoffmann uint32_t htest; 96f1ae32a1SGerd Hoffmann 97f1ae32a1SGerd Hoffmann /* SM501 local memory offset */ 989ac6a217SDavid Gibson dma_addr_t localmem_base; 99f1ae32a1SGerd Hoffmann 100f1ae32a1SGerd Hoffmann /* Active packets. */ 101f1ae32a1SGerd Hoffmann uint32_t old_ctl; 102f1ae32a1SGerd Hoffmann USBPacket usb_packet; 103f1ae32a1SGerd Hoffmann uint8_t usb_buf[8192]; 104f1ae32a1SGerd Hoffmann uint32_t async_td; 10569e25d26SAlexey Kardashevskiy bool async_complete; 106f1ae32a1SGerd Hoffmann 107f1ae32a1SGerd Hoffmann } OHCIState; 108f1ae32a1SGerd Hoffmann 109f1ae32a1SGerd Hoffmann /* Host Controller Communications Area */ 110f1ae32a1SGerd Hoffmann struct ohci_hcca { 111f1ae32a1SGerd Hoffmann uint32_t intr[32]; 112f1ae32a1SGerd Hoffmann uint16_t frame, pad; 113f1ae32a1SGerd Hoffmann uint32_t done; 114f1ae32a1SGerd Hoffmann }; 11586e18caeSWei Yang #define HCCA_WRITEBACK_OFFSET offsetof(struct ohci_hcca, frame) 11686e18caeSWei Yang #define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */ 11786e18caeSWei Yang 11886e18caeSWei Yang #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head) 11986e18caeSWei Yang #define ED_WBACK_SIZE 4 120f1ae32a1SGerd Hoffmann 121f1ae32a1SGerd Hoffmann static void ohci_bus_stop(OHCIState *ohci); 122f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); 123f1ae32a1SGerd Hoffmann 124f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Endpoint Desciptor. */ 125f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_SHIFT 0 126f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT) 127f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_SHIFT 7 128f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT) 129f1ae32a1SGerd Hoffmann #define OHCI_ED_D_SHIFT 11 130f1ae32a1SGerd Hoffmann #define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT) 131f1ae32a1SGerd Hoffmann #define OHCI_ED_S (1<<13) 132f1ae32a1SGerd Hoffmann #define OHCI_ED_K (1<<14) 133f1ae32a1SGerd Hoffmann #define OHCI_ED_F (1<<15) 134f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_SHIFT 16 135f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_MASK (0x7ff<<OHCI_ED_MPS_SHIFT) 136f1ae32a1SGerd Hoffmann 137f1ae32a1SGerd Hoffmann /* Flags in the head field of an Endpoint Desciptor. */ 138f1ae32a1SGerd Hoffmann #define OHCI_ED_H 1 139f1ae32a1SGerd Hoffmann #define OHCI_ED_C 2 140f1ae32a1SGerd Hoffmann 141f1ae32a1SGerd Hoffmann /* Bitfields for the first word of a Transfer Desciptor. */ 142f1ae32a1SGerd Hoffmann #define OHCI_TD_R (1<<18) 143f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_SHIFT 19 144f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT) 145f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_SHIFT 21 146f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT) 147f1ae32a1SGerd Hoffmann #define OHCI_TD_T0 (1<<24) 148f1ae32a1SGerd Hoffmann #define OHCI_TD_T1 (1<<25) 149f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_SHIFT 26 150f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT) 151f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_SHIFT 28 152f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT) 153f1ae32a1SGerd Hoffmann 154f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Isochronous Transfer Desciptor. */ 155f1ae32a1SGerd Hoffmann /* CC & DI - same as in the General Transfer Desciptor */ 156f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_SHIFT 0 157f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT) 158f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_SHIFT 24 159f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT) 160f1ae32a1SGerd Hoffmann 161f1ae32a1SGerd Hoffmann /* Isochronous Transfer Desciptor - Offset / PacketStatusWord */ 162f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_SHIFT 12 163f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT) 164f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_SHIFT 0 165f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT) 166f1ae32a1SGerd Hoffmann 167f1ae32a1SGerd Hoffmann #define OHCI_PAGE_MASK 0xfffff000 168f1ae32a1SGerd Hoffmann #define OHCI_OFFSET_MASK 0xfff 169f1ae32a1SGerd Hoffmann 170f1ae32a1SGerd Hoffmann #define OHCI_DPTR_MASK 0xfffffff0 171f1ae32a1SGerd Hoffmann 172f1ae32a1SGerd Hoffmann #define OHCI_BM(val, field) \ 173f1ae32a1SGerd Hoffmann (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT) 174f1ae32a1SGerd Hoffmann 175f1ae32a1SGerd Hoffmann #define OHCI_SET_BM(val, field, newval) do { \ 176f1ae32a1SGerd Hoffmann val &= ~OHCI_##field##_MASK; \ 177f1ae32a1SGerd Hoffmann val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ 178f1ae32a1SGerd Hoffmann } while(0) 179f1ae32a1SGerd Hoffmann 180f1ae32a1SGerd Hoffmann /* endpoint descriptor */ 181f1ae32a1SGerd Hoffmann struct ohci_ed { 182f1ae32a1SGerd Hoffmann uint32_t flags; 183f1ae32a1SGerd Hoffmann uint32_t tail; 184f1ae32a1SGerd Hoffmann uint32_t head; 185f1ae32a1SGerd Hoffmann uint32_t next; 186f1ae32a1SGerd Hoffmann }; 187f1ae32a1SGerd Hoffmann 188f1ae32a1SGerd Hoffmann /* General transfer descriptor */ 189f1ae32a1SGerd Hoffmann struct ohci_td { 190f1ae32a1SGerd Hoffmann uint32_t flags; 191f1ae32a1SGerd Hoffmann uint32_t cbp; 192f1ae32a1SGerd Hoffmann uint32_t next; 193f1ae32a1SGerd Hoffmann uint32_t be; 194f1ae32a1SGerd Hoffmann }; 195f1ae32a1SGerd Hoffmann 196f1ae32a1SGerd Hoffmann /* Isochronous transfer descriptor */ 197f1ae32a1SGerd Hoffmann struct ohci_iso_td { 198f1ae32a1SGerd Hoffmann uint32_t flags; 199f1ae32a1SGerd Hoffmann uint32_t bp; 200f1ae32a1SGerd Hoffmann uint32_t next; 201f1ae32a1SGerd Hoffmann uint32_t be; 202f1ae32a1SGerd Hoffmann uint16_t offset[8]; 203f1ae32a1SGerd Hoffmann }; 204f1ae32a1SGerd Hoffmann 205f1ae32a1SGerd Hoffmann #define USB_HZ 12000000 206f1ae32a1SGerd Hoffmann 207f1ae32a1SGerd Hoffmann /* OHCI Local stuff */ 208f1ae32a1SGerd Hoffmann #define OHCI_CTL_CBSR ((1<<0)|(1<<1)) 209f1ae32a1SGerd Hoffmann #define OHCI_CTL_PLE (1<<2) 210f1ae32a1SGerd Hoffmann #define OHCI_CTL_IE (1<<3) 211f1ae32a1SGerd Hoffmann #define OHCI_CTL_CLE (1<<4) 212f1ae32a1SGerd Hoffmann #define OHCI_CTL_BLE (1<<5) 213f1ae32a1SGerd Hoffmann #define OHCI_CTL_HCFS ((1<<6)|(1<<7)) 214f1ae32a1SGerd Hoffmann #define OHCI_USB_RESET 0x00 215f1ae32a1SGerd Hoffmann #define OHCI_USB_RESUME 0x40 216f1ae32a1SGerd Hoffmann #define OHCI_USB_OPERATIONAL 0x80 217f1ae32a1SGerd Hoffmann #define OHCI_USB_SUSPEND 0xc0 218f1ae32a1SGerd Hoffmann #define OHCI_CTL_IR (1<<8) 219f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWC (1<<9) 220f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWE (1<<10) 221f1ae32a1SGerd Hoffmann 222f1ae32a1SGerd Hoffmann #define OHCI_STATUS_HCR (1<<0) 223f1ae32a1SGerd Hoffmann #define OHCI_STATUS_CLF (1<<1) 224f1ae32a1SGerd Hoffmann #define OHCI_STATUS_BLF (1<<2) 225f1ae32a1SGerd Hoffmann #define OHCI_STATUS_OCR (1<<3) 226f1ae32a1SGerd Hoffmann #define OHCI_STATUS_SOC ((1<<6)|(1<<7)) 227f1ae32a1SGerd Hoffmann 22800b01793SPeter Maydell #define OHCI_INTR_SO (1U<<0) /* Scheduling overrun */ 22900b01793SPeter Maydell #define OHCI_INTR_WD (1U<<1) /* HcDoneHead writeback */ 23000b01793SPeter Maydell #define OHCI_INTR_SF (1U<<2) /* Start of frame */ 23100b01793SPeter Maydell #define OHCI_INTR_RD (1U<<3) /* Resume detect */ 23200b01793SPeter Maydell #define OHCI_INTR_UE (1U<<4) /* Unrecoverable error */ 23300b01793SPeter Maydell #define OHCI_INTR_FNO (1U<<5) /* Frame number overflow */ 23400b01793SPeter Maydell #define OHCI_INTR_RHSC (1U<<6) /* Root hub status change */ 23500b01793SPeter Maydell #define OHCI_INTR_OC (1U<<30) /* Ownership change */ 23600b01793SPeter Maydell #define OHCI_INTR_MIE (1U<<31) /* Master Interrupt Enable */ 237f1ae32a1SGerd Hoffmann 238f1ae32a1SGerd Hoffmann #define OHCI_HCCA_SIZE 0x100 239f1ae32a1SGerd Hoffmann #define OHCI_HCCA_MASK 0xffffff00 240f1ae32a1SGerd Hoffmann 241f1ae32a1SGerd Hoffmann #define OHCI_EDPTR_MASK 0xfffffff0 242f1ae32a1SGerd Hoffmann 243f1ae32a1SGerd Hoffmann #define OHCI_FMI_FI 0x00003fff 244f1ae32a1SGerd Hoffmann #define OHCI_FMI_FSMPS 0xffff0000 245f1ae32a1SGerd Hoffmann #define OHCI_FMI_FIT 0x80000000 246f1ae32a1SGerd Hoffmann 24700b01793SPeter Maydell #define OHCI_FR_RT (1U<<31) 248f1ae32a1SGerd Hoffmann 249f1ae32a1SGerd Hoffmann #define OHCI_LS_THRESH 0x628 250f1ae32a1SGerd Hoffmann 251f1ae32a1SGerd Hoffmann #define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ 252f1ae32a1SGerd Hoffmann #define OHCI_RHA_PSM (1<<8) 253f1ae32a1SGerd Hoffmann #define OHCI_RHA_NPS (1<<9) 254f1ae32a1SGerd Hoffmann #define OHCI_RHA_DT (1<<10) 255f1ae32a1SGerd Hoffmann #define OHCI_RHA_OCPM (1<<11) 256f1ae32a1SGerd Hoffmann #define OHCI_RHA_NOCP (1<<12) 257f1ae32a1SGerd Hoffmann #define OHCI_RHA_POTPGT_MASK 0xff000000 258f1ae32a1SGerd Hoffmann 25900b01793SPeter Maydell #define OHCI_RHS_LPS (1U<<0) 26000b01793SPeter Maydell #define OHCI_RHS_OCI (1U<<1) 26100b01793SPeter Maydell #define OHCI_RHS_DRWE (1U<<15) 26200b01793SPeter Maydell #define OHCI_RHS_LPSC (1U<<16) 26300b01793SPeter Maydell #define OHCI_RHS_OCIC (1U<<17) 26400b01793SPeter Maydell #define OHCI_RHS_CRWE (1U<<31) 265f1ae32a1SGerd Hoffmann 266f1ae32a1SGerd Hoffmann #define OHCI_PORT_CCS (1<<0) 267f1ae32a1SGerd Hoffmann #define OHCI_PORT_PES (1<<1) 268f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSS (1<<2) 269f1ae32a1SGerd Hoffmann #define OHCI_PORT_POCI (1<<3) 270f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRS (1<<4) 271f1ae32a1SGerd Hoffmann #define OHCI_PORT_PPS (1<<8) 272f1ae32a1SGerd Hoffmann #define OHCI_PORT_LSDA (1<<9) 273f1ae32a1SGerd Hoffmann #define OHCI_PORT_CSC (1<<16) 274f1ae32a1SGerd Hoffmann #define OHCI_PORT_PESC (1<<17) 275f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSSC (1<<18) 276f1ae32a1SGerd Hoffmann #define OHCI_PORT_OCIC (1<<19) 277f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRSC (1<<20) 278f1ae32a1SGerd Hoffmann #define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ 279f1ae32a1SGerd Hoffmann |OHCI_PORT_OCIC|OHCI_PORT_PRSC) 280f1ae32a1SGerd Hoffmann 281f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_SETUP 0x0 282f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_OUT 0x1 283f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_IN 0x2 284f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_RESERVED 0x3 285f1ae32a1SGerd Hoffmann 286f1ae32a1SGerd Hoffmann #define OHCI_CC_NOERROR 0x0 287f1ae32a1SGerd Hoffmann #define OHCI_CC_CRC 0x1 288f1ae32a1SGerd Hoffmann #define OHCI_CC_BITSTUFFING 0x2 289f1ae32a1SGerd Hoffmann #define OHCI_CC_DATATOGGLEMISMATCH 0x3 290f1ae32a1SGerd Hoffmann #define OHCI_CC_STALL 0x4 291f1ae32a1SGerd Hoffmann #define OHCI_CC_DEVICENOTRESPONDING 0x5 292f1ae32a1SGerd Hoffmann #define OHCI_CC_PIDCHECKFAILURE 0x6 293f1ae32a1SGerd Hoffmann #define OHCI_CC_UNDEXPETEDPID 0x7 294f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAOVERRUN 0x8 295f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAUNDERRUN 0x9 296f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFEROVERRUN 0xc 297f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFERUNDERRUN 0xd 298f1ae32a1SGerd Hoffmann 299f1ae32a1SGerd Hoffmann #define OHCI_HRESET_FSBIR (1 << 0) 300f1ae32a1SGerd Hoffmann 301cf66ee8eSAlexey Kardashevskiy static void ohci_die(OHCIState *ohci); 302cf66ee8eSAlexey Kardashevskiy 303f1ae32a1SGerd Hoffmann /* Update IRQ levels */ 304f1ae32a1SGerd Hoffmann static inline void ohci_intr_update(OHCIState *ohci) 305f1ae32a1SGerd Hoffmann { 306f1ae32a1SGerd Hoffmann int level = 0; 307f1ae32a1SGerd Hoffmann 308f1ae32a1SGerd Hoffmann if ((ohci->intr & OHCI_INTR_MIE) && 309f1ae32a1SGerd Hoffmann (ohci->intr_status & ohci->intr)) 310f1ae32a1SGerd Hoffmann level = 1; 311f1ae32a1SGerd Hoffmann 312f1ae32a1SGerd Hoffmann qemu_set_irq(ohci->irq, level); 313f1ae32a1SGerd Hoffmann } 314f1ae32a1SGerd Hoffmann 315f1ae32a1SGerd Hoffmann /* Set an interrupt */ 316f1ae32a1SGerd Hoffmann static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) 317f1ae32a1SGerd Hoffmann { 318f1ae32a1SGerd Hoffmann ohci->intr_status |= intr; 319f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 320f1ae32a1SGerd Hoffmann } 321f1ae32a1SGerd Hoffmann 322f1ae32a1SGerd Hoffmann /* Attach or detach a device on a root hub port. */ 323f1ae32a1SGerd Hoffmann static void ohci_attach(USBPort *port1) 324f1ae32a1SGerd Hoffmann { 325f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 326f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 327f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 328f1ae32a1SGerd Hoffmann 329f1ae32a1SGerd Hoffmann /* set connect status */ 330f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; 331f1ae32a1SGerd Hoffmann 332f1ae32a1SGerd Hoffmann /* update speed */ 333f1ae32a1SGerd Hoffmann if (port->port.dev->speed == USB_SPEED_LOW) { 334f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_LSDA; 335f1ae32a1SGerd Hoffmann } else { 336f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_LSDA; 337f1ae32a1SGerd Hoffmann } 338f1ae32a1SGerd Hoffmann 339f1ae32a1SGerd Hoffmann /* notify of remote-wakeup */ 340f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 341f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RD); 342f1ae32a1SGerd Hoffmann } 343f1ae32a1SGerd Hoffmann 344dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_attach(port1->index); 345f1ae32a1SGerd Hoffmann 346f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 347f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 348f1ae32a1SGerd Hoffmann } 349f1ae32a1SGerd Hoffmann } 350f1ae32a1SGerd Hoffmann 351f1ae32a1SGerd Hoffmann static void ohci_detach(USBPort *port1) 352f1ae32a1SGerd Hoffmann { 353f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 354f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 355f1ae32a1SGerd Hoffmann uint32_t old_state = port->ctrl; 356f1ae32a1SGerd Hoffmann 357f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, port1->dev); 358f1ae32a1SGerd Hoffmann 359f1ae32a1SGerd Hoffmann /* set connect status */ 360f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_CCS) { 361f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_CCS; 362f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_CSC; 363f1ae32a1SGerd Hoffmann } 364f1ae32a1SGerd Hoffmann /* disable port */ 365f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PES) { 366f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 367f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PESC; 368f1ae32a1SGerd Hoffmann } 369dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_detach(port1->index); 370f1ae32a1SGerd Hoffmann 371f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) { 372f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, OHCI_INTR_RHSC); 373f1ae32a1SGerd Hoffmann } 374f1ae32a1SGerd Hoffmann } 375f1ae32a1SGerd Hoffmann 376f1ae32a1SGerd Hoffmann static void ohci_wakeup(USBPort *port1) 377f1ae32a1SGerd Hoffmann { 378f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 379f1ae32a1SGerd Hoffmann OHCIPort *port = &s->rhport[port1->index]; 380f1ae32a1SGerd Hoffmann uint32_t intr = 0; 381f1ae32a1SGerd Hoffmann if (port->ctrl & OHCI_PORT_PSS) { 382dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_wakeup(port1->index); 383f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PSSC; 384f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PSS; 385f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RHSC; 386f1ae32a1SGerd Hoffmann } 387f1ae32a1SGerd Hoffmann /* Note that the controller can be suspended even if this port is not */ 388f1ae32a1SGerd Hoffmann if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { 389dc1f5988SAlexey Kardashevskiy trace_usb_ohci_remote_wakeup(s->name); 390f1ae32a1SGerd Hoffmann /* This is the one state transition the controller can do by itself */ 391f1ae32a1SGerd Hoffmann s->ctl &= ~OHCI_CTL_HCFS; 392f1ae32a1SGerd Hoffmann s->ctl |= OHCI_USB_RESUME; 393f1ae32a1SGerd Hoffmann /* In suspend mode only ResumeDetected is possible, not RHSC: 394f1ae32a1SGerd Hoffmann * see the OHCI spec 5.1.2.3. 395f1ae32a1SGerd Hoffmann */ 396f1ae32a1SGerd Hoffmann intr = OHCI_INTR_RD; 397f1ae32a1SGerd Hoffmann } 398f1ae32a1SGerd Hoffmann ohci_set_interrupt(s, intr); 399f1ae32a1SGerd Hoffmann } 400f1ae32a1SGerd Hoffmann 401f1ae32a1SGerd Hoffmann static void ohci_child_detach(USBPort *port1, USBDevice *child) 402f1ae32a1SGerd Hoffmann { 403f1ae32a1SGerd Hoffmann OHCIState *s = port1->opaque; 404f1ae32a1SGerd Hoffmann 405f1ae32a1SGerd Hoffmann ohci_async_cancel_device(s, child); 406f1ae32a1SGerd Hoffmann } 407f1ae32a1SGerd Hoffmann 408f1ae32a1SGerd Hoffmann static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr) 409f1ae32a1SGerd Hoffmann { 410f1ae32a1SGerd Hoffmann USBDevice *dev; 411f1ae32a1SGerd Hoffmann int i; 412f1ae32a1SGerd Hoffmann 413f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) { 414f1ae32a1SGerd Hoffmann if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) { 415f1ae32a1SGerd Hoffmann continue; 416f1ae32a1SGerd Hoffmann } 417f1ae32a1SGerd Hoffmann dev = usb_find_device(&ohci->rhport[i].port, addr); 418f1ae32a1SGerd Hoffmann if (dev != NULL) { 419f1ae32a1SGerd Hoffmann return dev; 420f1ae32a1SGerd Hoffmann } 421f1ae32a1SGerd Hoffmann } 422f1ae32a1SGerd Hoffmann return NULL; 423f1ae32a1SGerd Hoffmann } 424f1ae32a1SGerd Hoffmann 425f79738b0SHans de Goede static void ohci_stop_endpoints(OHCIState *ohci) 426f79738b0SHans de Goede { 427f79738b0SHans de Goede USBDevice *dev; 428f79738b0SHans de Goede int i, j; 429f79738b0SHans de Goede 430f79738b0SHans de Goede for (i = 0; i < ohci->num_ports; i++) { 431f79738b0SHans de Goede dev = ohci->rhport[i].port.dev; 432f79738b0SHans de Goede if (dev && dev->attached) { 433f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_ctl); 434f79738b0SHans de Goede for (j = 0; j < USB_MAX_ENDPOINTS; j++) { 435f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_in[j]); 436f79738b0SHans de Goede usb_device_ep_stopped(dev, &dev->ep_out[j]); 437f79738b0SHans de Goede } 438f79738b0SHans de Goede } 439f79738b0SHans de Goede } 440f79738b0SHans de Goede } 441f79738b0SHans de Goede 442f1ae32a1SGerd Hoffmann /* Reset the controller */ 443f1ae32a1SGerd Hoffmann static void ohci_reset(void *opaque) 444f1ae32a1SGerd Hoffmann { 445f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 446f1ae32a1SGerd Hoffmann OHCIPort *port; 447f1ae32a1SGerd Hoffmann int i; 448f1ae32a1SGerd Hoffmann 449f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 450f1ae32a1SGerd Hoffmann ohci->ctl = 0; 451f1ae32a1SGerd Hoffmann ohci->old_ctl = 0; 452f1ae32a1SGerd Hoffmann ohci->status = 0; 453f1ae32a1SGerd Hoffmann ohci->intr_status = 0; 454f1ae32a1SGerd Hoffmann ohci->intr = OHCI_INTR_MIE; 455f1ae32a1SGerd Hoffmann 456f1ae32a1SGerd Hoffmann ohci->hcca = 0; 457f1ae32a1SGerd Hoffmann ohci->ctrl_head = ohci->ctrl_cur = 0; 458f1ae32a1SGerd Hoffmann ohci->bulk_head = ohci->bulk_cur = 0; 459f1ae32a1SGerd Hoffmann ohci->per_cur = 0; 460f1ae32a1SGerd Hoffmann ohci->done = 0; 461f1ae32a1SGerd Hoffmann ohci->done_count = 7; 462f1ae32a1SGerd Hoffmann 463f1ae32a1SGerd Hoffmann /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? 464f1ae32a1SGerd Hoffmann * I took the value linux sets ... 465f1ae32a1SGerd Hoffmann */ 466f1ae32a1SGerd Hoffmann ohci->fsmps = 0x2778; 467f1ae32a1SGerd Hoffmann ohci->fi = 0x2edf; 468f1ae32a1SGerd Hoffmann ohci->fit = 0; 469f1ae32a1SGerd Hoffmann ohci->frt = 0; 470f1ae32a1SGerd Hoffmann ohci->frame_number = 0; 471f1ae32a1SGerd Hoffmann ohci->pstart = 0; 472f1ae32a1SGerd Hoffmann ohci->lst = OHCI_LS_THRESH; 473f1ae32a1SGerd Hoffmann 474f1ae32a1SGerd Hoffmann ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; 475f1ae32a1SGerd Hoffmann ohci->rhdesc_b = 0x0; /* Impl. specific */ 476f1ae32a1SGerd Hoffmann ohci->rhstatus = 0; 477f1ae32a1SGerd Hoffmann 478f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 479f1ae32a1SGerd Hoffmann { 480f1ae32a1SGerd Hoffmann port = &ohci->rhport[i]; 481f1ae32a1SGerd Hoffmann port->ctrl = 0; 482f1ae32a1SGerd Hoffmann if (port->port.dev && port->port.dev->attached) { 483f1ae32a1SGerd Hoffmann usb_port_reset(&port->port); 484f1ae32a1SGerd Hoffmann } 485f1ae32a1SGerd Hoffmann } 486f1ae32a1SGerd Hoffmann if (ohci->async_td) { 487f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 488f1ae32a1SGerd Hoffmann ohci->async_td = 0; 489f1ae32a1SGerd Hoffmann } 490f79738b0SHans de Goede ohci_stop_endpoints(ohci); 491dc1f5988SAlexey Kardashevskiy trace_usb_ohci_reset(ohci->name); 492f1ae32a1SGerd Hoffmann } 493f1ae32a1SGerd Hoffmann 494f1ae32a1SGerd Hoffmann /* Get an array of dwords from main memory */ 495f1ae32a1SGerd Hoffmann static inline int get_dwords(OHCIState *ohci, 4969ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 497f1ae32a1SGerd Hoffmann { 498f1ae32a1SGerd Hoffmann int i; 499f1ae32a1SGerd Hoffmann 500f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 501f1ae32a1SGerd Hoffmann 502f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 503cf66ee8eSAlexey Kardashevskiy if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { 504cf66ee8eSAlexey Kardashevskiy return -1; 505cf66ee8eSAlexey Kardashevskiy } 506f1ae32a1SGerd Hoffmann *buf = le32_to_cpu(*buf); 507f1ae32a1SGerd Hoffmann } 508f1ae32a1SGerd Hoffmann 509cf66ee8eSAlexey Kardashevskiy return 0; 510f1ae32a1SGerd Hoffmann } 511f1ae32a1SGerd Hoffmann 512f1ae32a1SGerd Hoffmann /* Put an array of dwords in to main memory */ 513f1ae32a1SGerd Hoffmann static inline int put_dwords(OHCIState *ohci, 5149ac6a217SDavid Gibson dma_addr_t addr, uint32_t *buf, int num) 515f1ae32a1SGerd Hoffmann { 516f1ae32a1SGerd Hoffmann int i; 517f1ae32a1SGerd Hoffmann 518f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 519f1ae32a1SGerd Hoffmann 520f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 521f1ae32a1SGerd Hoffmann uint32_t tmp = cpu_to_le32(*buf); 522cf66ee8eSAlexey Kardashevskiy if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { 523cf66ee8eSAlexey Kardashevskiy return -1; 524cf66ee8eSAlexey Kardashevskiy } 525f1ae32a1SGerd Hoffmann } 526f1ae32a1SGerd Hoffmann 527cf66ee8eSAlexey Kardashevskiy return 0; 528f1ae32a1SGerd Hoffmann } 529f1ae32a1SGerd Hoffmann 530f1ae32a1SGerd Hoffmann /* Get an array of words from main memory */ 531f1ae32a1SGerd Hoffmann static inline int get_words(OHCIState *ohci, 5329ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 533f1ae32a1SGerd Hoffmann { 534f1ae32a1SGerd Hoffmann int i; 535f1ae32a1SGerd Hoffmann 536f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 537f1ae32a1SGerd Hoffmann 538f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 539cf66ee8eSAlexey Kardashevskiy if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { 540cf66ee8eSAlexey Kardashevskiy return -1; 541cf66ee8eSAlexey Kardashevskiy } 542f1ae32a1SGerd Hoffmann *buf = le16_to_cpu(*buf); 543f1ae32a1SGerd Hoffmann } 544f1ae32a1SGerd Hoffmann 545cf66ee8eSAlexey Kardashevskiy return 0; 546f1ae32a1SGerd Hoffmann } 547f1ae32a1SGerd Hoffmann 548f1ae32a1SGerd Hoffmann /* Put an array of words in to main memory */ 549f1ae32a1SGerd Hoffmann static inline int put_words(OHCIState *ohci, 5509ac6a217SDavid Gibson dma_addr_t addr, uint16_t *buf, int num) 551f1ae32a1SGerd Hoffmann { 552f1ae32a1SGerd Hoffmann int i; 553f1ae32a1SGerd Hoffmann 554f1ae32a1SGerd Hoffmann addr += ohci->localmem_base; 555f1ae32a1SGerd Hoffmann 556f1ae32a1SGerd Hoffmann for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { 557f1ae32a1SGerd Hoffmann uint16_t tmp = cpu_to_le16(*buf); 558cf66ee8eSAlexey Kardashevskiy if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { 559cf66ee8eSAlexey Kardashevskiy return -1; 560cf66ee8eSAlexey Kardashevskiy } 561f1ae32a1SGerd Hoffmann } 562f1ae32a1SGerd Hoffmann 563cf66ee8eSAlexey Kardashevskiy return 0; 564f1ae32a1SGerd Hoffmann } 565f1ae32a1SGerd Hoffmann 566f1ae32a1SGerd Hoffmann static inline int ohci_read_ed(OHCIState *ohci, 5679ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 568f1ae32a1SGerd Hoffmann { 569f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2); 570f1ae32a1SGerd Hoffmann } 571f1ae32a1SGerd Hoffmann 572f1ae32a1SGerd Hoffmann static inline int ohci_read_td(OHCIState *ohci, 5739ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 574f1ae32a1SGerd Hoffmann { 575f1ae32a1SGerd Hoffmann return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 576f1ae32a1SGerd Hoffmann } 577f1ae32a1SGerd Hoffmann 578f1ae32a1SGerd Hoffmann static inline int ohci_read_iso_td(OHCIState *ohci, 5799ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 580f1ae32a1SGerd Hoffmann { 581cf66ee8eSAlexey Kardashevskiy return get_dwords(ohci, addr, (uint32_t *)td, 4) || 582cf66ee8eSAlexey Kardashevskiy get_words(ohci, addr + 16, td->offset, 8); 583f1ae32a1SGerd Hoffmann } 584f1ae32a1SGerd Hoffmann 585f1ae32a1SGerd Hoffmann static inline int ohci_read_hcca(OHCIState *ohci, 5869ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 587f1ae32a1SGerd Hoffmann { 588cf66ee8eSAlexey Kardashevskiy return dma_memory_read(ohci->as, addr + ohci->localmem_base, 589cf66ee8eSAlexey Kardashevskiy hcca, sizeof(*hcca)); 590f1ae32a1SGerd Hoffmann } 591f1ae32a1SGerd Hoffmann 592f1ae32a1SGerd Hoffmann static inline int ohci_put_ed(OHCIState *ohci, 5939ac6a217SDavid Gibson dma_addr_t addr, struct ohci_ed *ed) 594f1ae32a1SGerd Hoffmann { 59586e18caeSWei Yang /* ed->tail is under control of the HCD. 59686e18caeSWei Yang * Since just ed->head is changed by HC, just write back this 59786e18caeSWei Yang */ 59886e18caeSWei Yang 59986e18caeSWei Yang return put_dwords(ohci, addr + ED_WBACK_OFFSET, 60086e18caeSWei Yang (uint32_t *)((char *)ed + ED_WBACK_OFFSET), 60186e18caeSWei Yang ED_WBACK_SIZE >> 2); 602f1ae32a1SGerd Hoffmann } 603f1ae32a1SGerd Hoffmann 604f1ae32a1SGerd Hoffmann static inline int ohci_put_td(OHCIState *ohci, 6059ac6a217SDavid Gibson dma_addr_t addr, struct ohci_td *td) 606f1ae32a1SGerd Hoffmann { 607f1ae32a1SGerd Hoffmann return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2); 608f1ae32a1SGerd Hoffmann } 609f1ae32a1SGerd Hoffmann 610f1ae32a1SGerd Hoffmann static inline int ohci_put_iso_td(OHCIState *ohci, 6119ac6a217SDavid Gibson dma_addr_t addr, struct ohci_iso_td *td) 612f1ae32a1SGerd Hoffmann { 613cae7f29cSJack Un return put_dwords(ohci, addr, (uint32_t *)td, 4) || 614cae7f29cSJack Un put_words(ohci, addr + 16, td->offset, 8); 615f1ae32a1SGerd Hoffmann } 616f1ae32a1SGerd Hoffmann 617f1ae32a1SGerd Hoffmann static inline int ohci_put_hcca(OHCIState *ohci, 6189ac6a217SDavid Gibson dma_addr_t addr, struct ohci_hcca *hcca) 619f1ae32a1SGerd Hoffmann { 620cf66ee8eSAlexey Kardashevskiy return dma_memory_write(ohci->as, 6219ac6a217SDavid Gibson addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, 62286e18caeSWei Yang (char *)hcca + HCCA_WRITEBACK_OFFSET, 62386e18caeSWei Yang HCCA_WRITEBACK_SIZE); 624f1ae32a1SGerd Hoffmann } 625f1ae32a1SGerd Hoffmann 626f1ae32a1SGerd Hoffmann /* Read/Write the contents of a TD from/to main memory. */ 627cf66ee8eSAlexey Kardashevskiy static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, 6289ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 629f1ae32a1SGerd Hoffmann { 6309ac6a217SDavid Gibson dma_addr_t ptr, n; 631f1ae32a1SGerd Hoffmann 632f1ae32a1SGerd Hoffmann ptr = td->cbp; 633f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 634f1ae32a1SGerd Hoffmann if (n > len) 635f1ae32a1SGerd Hoffmann n = len; 636cf66ee8eSAlexey Kardashevskiy 637cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { 638cf66ee8eSAlexey Kardashevskiy return -1; 639cf66ee8eSAlexey Kardashevskiy } 640cf66ee8eSAlexey Kardashevskiy if (n == len) { 641cf66ee8eSAlexey Kardashevskiy return 0; 642cf66ee8eSAlexey Kardashevskiy } 643f1ae32a1SGerd Hoffmann ptr = td->be & ~0xfffu; 644f1ae32a1SGerd Hoffmann buf += n; 645cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 646cf66ee8eSAlexey Kardashevskiy len - n, dir)) { 647cf66ee8eSAlexey Kardashevskiy return -1; 648cf66ee8eSAlexey Kardashevskiy } 649cf66ee8eSAlexey Kardashevskiy return 0; 650f1ae32a1SGerd Hoffmann } 651f1ae32a1SGerd Hoffmann 652f1ae32a1SGerd Hoffmann /* Read/Write the contents of an ISO TD from/to main memory. */ 653cf66ee8eSAlexey Kardashevskiy static int ohci_copy_iso_td(OHCIState *ohci, 654f1ae32a1SGerd Hoffmann uint32_t start_addr, uint32_t end_addr, 6559ac6a217SDavid Gibson uint8_t *buf, int len, DMADirection dir) 656f1ae32a1SGerd Hoffmann { 6579ac6a217SDavid Gibson dma_addr_t ptr, n; 658f1ae32a1SGerd Hoffmann 659f1ae32a1SGerd Hoffmann ptr = start_addr; 660f1ae32a1SGerd Hoffmann n = 0x1000 - (ptr & 0xfff); 661f1ae32a1SGerd Hoffmann if (n > len) 662f1ae32a1SGerd Hoffmann n = len; 663cf66ee8eSAlexey Kardashevskiy 664cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { 665cf66ee8eSAlexey Kardashevskiy return -1; 666cf66ee8eSAlexey Kardashevskiy } 667cf66ee8eSAlexey Kardashevskiy if (n == len) { 668cf66ee8eSAlexey Kardashevskiy return 0; 669cf66ee8eSAlexey Kardashevskiy } 670f1ae32a1SGerd Hoffmann ptr = end_addr & ~0xfffu; 671f1ae32a1SGerd Hoffmann buf += n; 672cf66ee8eSAlexey Kardashevskiy if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, 673cf66ee8eSAlexey Kardashevskiy len - n, dir)) { 674cf66ee8eSAlexey Kardashevskiy return -1; 675cf66ee8eSAlexey Kardashevskiy } 676cf66ee8eSAlexey Kardashevskiy return 0; 677f1ae32a1SGerd Hoffmann } 678f1ae32a1SGerd Hoffmann 679f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion); 680f1ae32a1SGerd Hoffmann 681f1ae32a1SGerd Hoffmann static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) 682f1ae32a1SGerd Hoffmann { 683f1ae32a1SGerd Hoffmann OHCIState *ohci = container_of(packet, OHCIState, usb_packet); 684dc1f5988SAlexey Kardashevskiy 685dc1f5988SAlexey Kardashevskiy trace_usb_ohci_async_complete(); 68669e25d26SAlexey Kardashevskiy ohci->async_complete = true; 687f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 1); 688f1ae32a1SGerd Hoffmann } 689f1ae32a1SGerd Hoffmann 690f1ae32a1SGerd Hoffmann #define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b))) 691f1ae32a1SGerd Hoffmann 692f1ae32a1SGerd Hoffmann static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, 693f1ae32a1SGerd Hoffmann int completion) 694f1ae32a1SGerd Hoffmann { 695f1ae32a1SGerd Hoffmann int dir; 696f1ae32a1SGerd Hoffmann size_t len = 0; 697f1ae32a1SGerd Hoffmann const char *str = NULL; 698f1ae32a1SGerd Hoffmann int pid; 699f1ae32a1SGerd Hoffmann int ret; 700f1ae32a1SGerd Hoffmann int i; 701f1ae32a1SGerd Hoffmann USBDevice *dev; 702f1ae32a1SGerd Hoffmann USBEndpoint *ep; 703f1ae32a1SGerd Hoffmann struct ohci_iso_td iso_td; 704f1ae32a1SGerd Hoffmann uint32_t addr; 705f1ae32a1SGerd Hoffmann uint16_t starting_frame; 706f1ae32a1SGerd Hoffmann int16_t relative_frame_number; 707f1ae32a1SGerd Hoffmann int frame_count; 708f1ae32a1SGerd Hoffmann uint32_t start_offset, next_offset, end_offset = 0; 709f1ae32a1SGerd Hoffmann uint32_t start_addr, end_addr; 710f1ae32a1SGerd Hoffmann 711f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 712f1ae32a1SGerd Hoffmann 713cf66ee8eSAlexey Kardashevskiy if (ohci_read_iso_td(ohci, addr, &iso_td)) { 714dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_read_failed(addr); 715cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 716f1ae32a1SGerd Hoffmann return 0; 717f1ae32a1SGerd Hoffmann } 718f1ae32a1SGerd Hoffmann 719f1ae32a1SGerd Hoffmann starting_frame = OHCI_BM(iso_td.flags, TD_SF); 720f1ae32a1SGerd Hoffmann frame_count = OHCI_BM(iso_td.flags, TD_FC); 721f1ae32a1SGerd Hoffmann relative_frame_number = USUB(ohci->frame_number, starting_frame); 722f1ae32a1SGerd Hoffmann 723dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_head( 724f1ae32a1SGerd Hoffmann ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK, 725f1ae32a1SGerd Hoffmann iso_td.flags, iso_td.bp, iso_td.next, iso_td.be, 726f1ae32a1SGerd Hoffmann ohci->frame_number, starting_frame, 727bc0d104cSAlex Bennée frame_count, relative_frame_number); 7283af8f177SAlexey Kardashevskiy trace_usb_ohci_iso_td_head_offset( 7293af8f177SAlexey Kardashevskiy iso_td.offset[0], iso_td.offset[1], 7303af8f177SAlexey Kardashevskiy iso_td.offset[2], iso_td.offset[3], 7313af8f177SAlexey Kardashevskiy iso_td.offset[4], iso_td.offset[5], 7323af8f177SAlexey Kardashevskiy iso_td.offset[6], iso_td.offset[7]); 733f1ae32a1SGerd Hoffmann 734f1ae32a1SGerd Hoffmann if (relative_frame_number < 0) { 735dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number); 736f1ae32a1SGerd Hoffmann return 1; 737f1ae32a1SGerd Hoffmann } else if (relative_frame_number > frame_count) { 738f1ae32a1SGerd Hoffmann /* ISO TD expired - retire the TD to the Done Queue and continue with 739f1ae32a1SGerd Hoffmann the next ISO TD of the same ED */ 740dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number, 741f1ae32a1SGerd Hoffmann frame_count); 742f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 743f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 744f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 745f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 746f1ae32a1SGerd Hoffmann ohci->done = addr; 747f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 748f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 749f1ae32a1SGerd Hoffmann ohci->done_count = i; 750cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 751cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 752cf66ee8eSAlexey Kardashevskiy return 1; 753cf66ee8eSAlexey Kardashevskiy } 754f1ae32a1SGerd Hoffmann return 0; 755f1ae32a1SGerd Hoffmann } 756f1ae32a1SGerd Hoffmann 757f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 758f1ae32a1SGerd Hoffmann switch (dir) { 759f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 760f1ae32a1SGerd Hoffmann str = "in"; 761f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 762f1ae32a1SGerd Hoffmann break; 763f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 764f1ae32a1SGerd Hoffmann str = "out"; 765f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 766f1ae32a1SGerd Hoffmann break; 767f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 768f1ae32a1SGerd Hoffmann str = "setup"; 769f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 770f1ae32a1SGerd Hoffmann break; 771f1ae32a1SGerd Hoffmann default: 772dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_direction(dir); 773f1ae32a1SGerd Hoffmann return 1; 774f1ae32a1SGerd Hoffmann } 775f1ae32a1SGerd Hoffmann 776f1ae32a1SGerd Hoffmann if (!iso_td.bp || !iso_td.be) { 777dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be); 778f1ae32a1SGerd Hoffmann return 1; 779f1ae32a1SGerd Hoffmann } 780f1ae32a1SGerd Hoffmann 781f1ae32a1SGerd Hoffmann start_offset = iso_td.offset[relative_frame_number]; 782f1ae32a1SGerd Hoffmann next_offset = iso_td.offset[relative_frame_number + 1]; 783f1ae32a1SGerd Hoffmann 784f1ae32a1SGerd Hoffmann if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || 785f1ae32a1SGerd Hoffmann ((relative_frame_number < frame_count) && 786f1ae32a1SGerd Hoffmann !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) { 787dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset); 788f1ae32a1SGerd Hoffmann return 1; 789f1ae32a1SGerd Hoffmann } 790f1ae32a1SGerd Hoffmann 791f1ae32a1SGerd Hoffmann if ((relative_frame_number < frame_count) && (start_offset > next_offset)) { 792dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset); 793f1ae32a1SGerd Hoffmann return 1; 794f1ae32a1SGerd Hoffmann } 795f1ae32a1SGerd Hoffmann 796f1ae32a1SGerd Hoffmann if ((start_offset & 0x1000) == 0) { 797f1ae32a1SGerd Hoffmann start_addr = (iso_td.bp & OHCI_PAGE_MASK) | 798f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 799f1ae32a1SGerd Hoffmann } else { 800f1ae32a1SGerd Hoffmann start_addr = (iso_td.be & OHCI_PAGE_MASK) | 801f1ae32a1SGerd Hoffmann (start_offset & OHCI_OFFSET_MASK); 802f1ae32a1SGerd Hoffmann } 803f1ae32a1SGerd Hoffmann 804f1ae32a1SGerd Hoffmann if (relative_frame_number < frame_count) { 805f1ae32a1SGerd Hoffmann end_offset = next_offset - 1; 806f1ae32a1SGerd Hoffmann if ((end_offset & 0x1000) == 0) { 807f1ae32a1SGerd Hoffmann end_addr = (iso_td.bp & OHCI_PAGE_MASK) | 808f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 809f1ae32a1SGerd Hoffmann } else { 810f1ae32a1SGerd Hoffmann end_addr = (iso_td.be & OHCI_PAGE_MASK) | 811f1ae32a1SGerd Hoffmann (end_offset & OHCI_OFFSET_MASK); 812f1ae32a1SGerd Hoffmann } 813f1ae32a1SGerd Hoffmann } else { 814f1ae32a1SGerd Hoffmann /* Last packet in the ISO TD */ 815f1ae32a1SGerd Hoffmann end_addr = iso_td.be; 816f1ae32a1SGerd Hoffmann } 817f1ae32a1SGerd Hoffmann 818f1ae32a1SGerd Hoffmann if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { 819f1ae32a1SGerd Hoffmann len = (end_addr & OHCI_OFFSET_MASK) + 0x1001 820f1ae32a1SGerd Hoffmann - (start_addr & OHCI_OFFSET_MASK); 821f1ae32a1SGerd Hoffmann } else { 822f1ae32a1SGerd Hoffmann len = end_addr - start_addr + 1; 823f1ae32a1SGerd Hoffmann } 824f1ae32a1SGerd Hoffmann 825f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 826cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 827cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 828cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 829cf66ee8eSAlexey Kardashevskiy return 1; 830cf66ee8eSAlexey Kardashevskiy } 831f1ae32a1SGerd Hoffmann } 832f1ae32a1SGerd Hoffmann 8339a77a0f5SHans de Goede if (!completion) { 834a6fb2ddbSHans de Goede bool int_req = relative_frame_number == frame_count && 835a6fb2ddbSHans de Goede OHCI_BM(iso_td.flags, TD_DI) == 0; 836f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 837f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 8388550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req); 839f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); 8409a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 8419a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 84236dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 843f1ae32a1SGerd Hoffmann return 1; 844f1ae32a1SGerd Hoffmann } 845f1ae32a1SGerd Hoffmann } 8469a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 8479a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 8489a77a0f5SHans de Goede } else { 8499a77a0f5SHans de Goede ret = ohci->usb_packet.status; 8509a77a0f5SHans de Goede } 851f1ae32a1SGerd Hoffmann 852dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr, 853dc1f5988SAlexey Kardashevskiy str, len, ret); 854f1ae32a1SGerd Hoffmann 855f1ae32a1SGerd Hoffmann /* Writeback */ 856f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) { 857f1ae32a1SGerd Hoffmann /* IN transfer succeeded */ 858cf66ee8eSAlexey Kardashevskiy if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 859cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 860cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 861cf66ee8eSAlexey Kardashevskiy return 1; 862cf66ee8eSAlexey Kardashevskiy } 863f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 864f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 865f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret); 866f1ae32a1SGerd Hoffmann } else if (dir == OHCI_TD_DIR_OUT && ret == len) { 867f1ae32a1SGerd Hoffmann /* OUT transfer succeeded */ 868f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 869f1ae32a1SGerd Hoffmann OHCI_CC_NOERROR); 870f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); 871f1ae32a1SGerd Hoffmann } else { 872f1ae32a1SGerd Hoffmann if (ret > (ssize_t) len) { 873dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_overrun(ret, len); 874f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 875f1ae32a1SGerd Hoffmann OHCI_CC_DATAOVERRUN); 876f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 877f1ae32a1SGerd Hoffmann len); 878f1ae32a1SGerd Hoffmann } else if (ret >= 0) { 879dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_data_underrun(ret); 880f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 881f1ae32a1SGerd Hoffmann OHCI_CC_DATAUNDERRUN); 882f1ae32a1SGerd Hoffmann } else { 883f1ae32a1SGerd Hoffmann switch (ret) { 884f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 885f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 886f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 887f1ae32a1SGerd Hoffmann OHCI_CC_DEVICENOTRESPONDING); 888f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 889f1ae32a1SGerd Hoffmann 0); 890f1ae32a1SGerd Hoffmann break; 891f1ae32a1SGerd Hoffmann case USB_RET_NAK: 892f1ae32a1SGerd Hoffmann case USB_RET_STALL: 893dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_nak(ret); 894f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 895f1ae32a1SGerd Hoffmann OHCI_CC_STALL); 896f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 897f1ae32a1SGerd Hoffmann 0); 898f1ae32a1SGerd Hoffmann break; 899f1ae32a1SGerd Hoffmann default: 900dc1f5988SAlexey Kardashevskiy trace_usb_ohci_iso_td_bad_response(ret); 901f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, 902f1ae32a1SGerd Hoffmann OHCI_CC_UNDEXPETEDPID); 903f1ae32a1SGerd Hoffmann break; 904f1ae32a1SGerd Hoffmann } 905f1ae32a1SGerd Hoffmann } 906f1ae32a1SGerd Hoffmann } 907f1ae32a1SGerd Hoffmann 908f1ae32a1SGerd Hoffmann if (relative_frame_number == frame_count) { 909f1ae32a1SGerd Hoffmann /* Last data packet of ISO TD - retire the TD to the Done Queue */ 910f1ae32a1SGerd Hoffmann OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR); 911f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 912f1ae32a1SGerd Hoffmann ed->head |= (iso_td.next & OHCI_DPTR_MASK); 913f1ae32a1SGerd Hoffmann iso_td.next = ohci->done; 914f1ae32a1SGerd Hoffmann ohci->done = addr; 915f1ae32a1SGerd Hoffmann i = OHCI_BM(iso_td.flags, TD_DI); 916f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 917f1ae32a1SGerd Hoffmann ohci->done_count = i; 918f1ae32a1SGerd Hoffmann } 919cf66ee8eSAlexey Kardashevskiy if (ohci_put_iso_td(ohci, addr, &iso_td)) { 920cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 921cf66ee8eSAlexey Kardashevskiy } 922f1ae32a1SGerd Hoffmann return 1; 923f1ae32a1SGerd Hoffmann } 924f1ae32a1SGerd Hoffmann 925dc1f5988SAlexey Kardashevskiy #ifdef trace_event_get_state 926dc1f5988SAlexey Kardashevskiy static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) 927dc1f5988SAlexey Kardashevskiy { 928dc1f5988SAlexey Kardashevskiy bool print16 = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_SHORT); 929dc1f5988SAlexey Kardashevskiy bool printall = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_FULL); 930dc1f5988SAlexey Kardashevskiy const int width = 16; 931dc1f5988SAlexey Kardashevskiy int i; 932dc1f5988SAlexey Kardashevskiy char tmp[3 * width + 1]; 933dc1f5988SAlexey Kardashevskiy char *p = tmp; 934dc1f5988SAlexey Kardashevskiy 935dc1f5988SAlexey Kardashevskiy if (!printall && !print16) { 936dc1f5988SAlexey Kardashevskiy return; 937dc1f5988SAlexey Kardashevskiy } 938dc1f5988SAlexey Kardashevskiy 939dc1f5988SAlexey Kardashevskiy for (i = 0; ; i++) { 940dc1f5988SAlexey Kardashevskiy if (i && (!(i % width) || (i == len))) { 941dc1f5988SAlexey Kardashevskiy if (!printall) { 942dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_short(msg, tmp); 943dc1f5988SAlexey Kardashevskiy break; 944dc1f5988SAlexey Kardashevskiy } 945dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_full(msg, tmp); 946dc1f5988SAlexey Kardashevskiy p = tmp; 947dc1f5988SAlexey Kardashevskiy *p = 0; 948dc1f5988SAlexey Kardashevskiy } 949dc1f5988SAlexey Kardashevskiy if (i == len) { 950dc1f5988SAlexey Kardashevskiy break; 951dc1f5988SAlexey Kardashevskiy } 952dc1f5988SAlexey Kardashevskiy 953dc1f5988SAlexey Kardashevskiy p += sprintf(p, " %.2x", buf[i]); 954dc1f5988SAlexey Kardashevskiy } 955dc1f5988SAlexey Kardashevskiy } 956dc1f5988SAlexey Kardashevskiy #else 957dc1f5988SAlexey Kardashevskiy static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len) 958dc1f5988SAlexey Kardashevskiy { 959dc1f5988SAlexey Kardashevskiy } 960dc1f5988SAlexey Kardashevskiy #endif 961dc1f5988SAlexey Kardashevskiy 962f1ae32a1SGerd Hoffmann /* Service a transport descriptor. 963f1ae32a1SGerd Hoffmann Returns nonzero to terminate processing of this endpoint. */ 964f1ae32a1SGerd Hoffmann 965f1ae32a1SGerd Hoffmann static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) 966f1ae32a1SGerd Hoffmann { 967f1ae32a1SGerd Hoffmann int dir; 968f1ae32a1SGerd Hoffmann size_t len = 0, pktlen = 0; 969f1ae32a1SGerd Hoffmann const char *str = NULL; 970f1ae32a1SGerd Hoffmann int pid; 971f1ae32a1SGerd Hoffmann int ret; 972f1ae32a1SGerd Hoffmann int i; 973f1ae32a1SGerd Hoffmann USBDevice *dev; 974f1ae32a1SGerd Hoffmann USBEndpoint *ep; 975f1ae32a1SGerd Hoffmann struct ohci_td td; 976f1ae32a1SGerd Hoffmann uint32_t addr; 977f1ae32a1SGerd Hoffmann int flag_r; 978f1ae32a1SGerd Hoffmann int completion; 979f1ae32a1SGerd Hoffmann 980f1ae32a1SGerd Hoffmann addr = ed->head & OHCI_DPTR_MASK; 981f1ae32a1SGerd Hoffmann /* See if this TD has already been submitted to the device. */ 982f1ae32a1SGerd Hoffmann completion = (addr == ohci->async_td); 983f1ae32a1SGerd Hoffmann if (completion && !ohci->async_complete) { 984dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_skip_async(); 985f1ae32a1SGerd Hoffmann return 1; 986f1ae32a1SGerd Hoffmann } 987cf66ee8eSAlexey Kardashevskiy if (ohci_read_td(ohci, addr, &td)) { 988dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_read_error(addr); 989cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 990f1ae32a1SGerd Hoffmann return 0; 991f1ae32a1SGerd Hoffmann } 992f1ae32a1SGerd Hoffmann 993f1ae32a1SGerd Hoffmann dir = OHCI_BM(ed->flags, ED_D); 994f1ae32a1SGerd Hoffmann switch (dir) { 995f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 996f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 997f1ae32a1SGerd Hoffmann /* Same value. */ 998f1ae32a1SGerd Hoffmann break; 999f1ae32a1SGerd Hoffmann default: 1000f1ae32a1SGerd Hoffmann dir = OHCI_BM(td.flags, TD_DP); 1001f1ae32a1SGerd Hoffmann break; 1002f1ae32a1SGerd Hoffmann } 1003f1ae32a1SGerd Hoffmann 1004f1ae32a1SGerd Hoffmann switch (dir) { 1005f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_IN: 1006f1ae32a1SGerd Hoffmann str = "in"; 1007f1ae32a1SGerd Hoffmann pid = USB_TOKEN_IN; 1008f1ae32a1SGerd Hoffmann break; 1009f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_OUT: 1010f1ae32a1SGerd Hoffmann str = "out"; 1011f1ae32a1SGerd Hoffmann pid = USB_TOKEN_OUT; 1012f1ae32a1SGerd Hoffmann break; 1013f1ae32a1SGerd Hoffmann case OHCI_TD_DIR_SETUP: 1014f1ae32a1SGerd Hoffmann str = "setup"; 1015f1ae32a1SGerd Hoffmann pid = USB_TOKEN_SETUP; 1016f1ae32a1SGerd Hoffmann break; 1017f1ae32a1SGerd Hoffmann default: 1018dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_direction(dir); 1019f1ae32a1SGerd Hoffmann return 1; 1020f1ae32a1SGerd Hoffmann } 1021f1ae32a1SGerd Hoffmann if (td.cbp && td.be) { 1022f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { 1023f1ae32a1SGerd Hoffmann len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); 1024f1ae32a1SGerd Hoffmann } else { 1025f1ae32a1SGerd Hoffmann len = (td.be - td.cbp) + 1; 1026f1ae32a1SGerd Hoffmann } 1027f1ae32a1SGerd Hoffmann 1028f1ae32a1SGerd Hoffmann pktlen = len; 1029f1ae32a1SGerd Hoffmann if (len && dir != OHCI_TD_DIR_IN) { 1030f1ae32a1SGerd Hoffmann /* The endpoint may not allow us to transfer it all now */ 1031f1ae32a1SGerd Hoffmann pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT; 1032f1ae32a1SGerd Hoffmann if (pktlen > len) { 1033f1ae32a1SGerd Hoffmann pktlen = len; 1034f1ae32a1SGerd Hoffmann } 1035f1ae32a1SGerd Hoffmann if (!completion) { 1036cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 1037cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_TO_DEVICE)) { 1038cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1039cf66ee8eSAlexey Kardashevskiy } 1040f1ae32a1SGerd Hoffmann } 1041f1ae32a1SGerd Hoffmann } 1042f1ae32a1SGerd Hoffmann } 1043f1ae32a1SGerd Hoffmann 1044f1ae32a1SGerd Hoffmann flag_r = (td.flags & OHCI_TD_R) != 0; 1045dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str, 1046dc1f5988SAlexey Kardashevskiy flag_r, td.cbp, td.be); 1047dc1f5988SAlexey Kardashevskiy ohci_td_pkt("OUT", ohci->usb_buf, pktlen); 1048f1ae32a1SGerd Hoffmann 1049f1ae32a1SGerd Hoffmann if (completion) { 1050f1ae32a1SGerd Hoffmann ohci->async_td = 0; 105169e25d26SAlexey Kardashevskiy ohci->async_complete = false; 1052f1ae32a1SGerd Hoffmann } else { 1053f1ae32a1SGerd Hoffmann if (ohci->async_td) { 1054f1ae32a1SGerd Hoffmann /* ??? The hardware should allow one active packet per 1055f1ae32a1SGerd Hoffmann endpoint. We only allow one active packet per controller. 1056f1ae32a1SGerd Hoffmann This should be sufficient as long as devices respond in a 1057f1ae32a1SGerd Hoffmann timely manner. 1058f1ae32a1SGerd Hoffmann */ 1059dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_too_many_pending(); 1060f1ae32a1SGerd Hoffmann return 1; 1061f1ae32a1SGerd Hoffmann } 1062f1ae32a1SGerd Hoffmann dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); 1063f1ae32a1SGerd Hoffmann ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); 10648550a02dSGerd Hoffmann usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r, 1065a6fb2ddbSHans de Goede OHCI_BM(td.flags, TD_DI) == 0); 1066f1ae32a1SGerd Hoffmann usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); 10679a77a0f5SHans de Goede usb_handle_packet(dev, &ohci->usb_packet); 1068dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_packet_status(ohci->usb_packet.status); 1069dc1f5988SAlexey Kardashevskiy 10709a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_ASYNC) { 107136dfe324SHans de Goede usb_device_flush_ep_queue(dev, ep); 1072f1ae32a1SGerd Hoffmann ohci->async_td = addr; 1073f1ae32a1SGerd Hoffmann return 1; 1074f1ae32a1SGerd Hoffmann } 1075f1ae32a1SGerd Hoffmann } 10769a77a0f5SHans de Goede if (ohci->usb_packet.status == USB_RET_SUCCESS) { 10779a77a0f5SHans de Goede ret = ohci->usb_packet.actual_length; 10789a77a0f5SHans de Goede } else { 10799a77a0f5SHans de Goede ret = ohci->usb_packet.status; 10809a77a0f5SHans de Goede } 10819a77a0f5SHans de Goede 1082f1ae32a1SGerd Hoffmann if (ret >= 0) { 1083f1ae32a1SGerd Hoffmann if (dir == OHCI_TD_DIR_IN) { 1084cf66ee8eSAlexey Kardashevskiy if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1085cf66ee8eSAlexey Kardashevskiy DMA_DIRECTION_FROM_DEVICE)) { 1086cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1087cf66ee8eSAlexey Kardashevskiy } 1088dc1f5988SAlexey Kardashevskiy ohci_td_pkt("IN", ohci->usb_buf, pktlen); 1089f1ae32a1SGerd Hoffmann } else { 1090f1ae32a1SGerd Hoffmann ret = pktlen; 1091f1ae32a1SGerd Hoffmann } 1092f1ae32a1SGerd Hoffmann } 1093f1ae32a1SGerd Hoffmann 1094f1ae32a1SGerd Hoffmann /* Writeback */ 1095f1ae32a1SGerd Hoffmann if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { 1096f1ae32a1SGerd Hoffmann /* Transmission succeeded. */ 1097f1ae32a1SGerd Hoffmann if (ret == len) { 1098f1ae32a1SGerd Hoffmann td.cbp = 0; 1099f1ae32a1SGerd Hoffmann } else { 1100f1ae32a1SGerd Hoffmann if ((td.cbp & 0xfff) + ret > 0xfff) { 1101f1ae32a1SGerd Hoffmann td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff); 1102f1ae32a1SGerd Hoffmann } else { 1103f1ae32a1SGerd Hoffmann td.cbp += ret; 1104f1ae32a1SGerd Hoffmann } 1105f1ae32a1SGerd Hoffmann } 1106f1ae32a1SGerd Hoffmann td.flags |= OHCI_TD_T1; 1107f1ae32a1SGerd Hoffmann td.flags ^= OHCI_TD_T0; 1108f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); 1109f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 0); 1110f1ae32a1SGerd Hoffmann 1111f1ae32a1SGerd Hoffmann if ((dir != OHCI_TD_DIR_IN) && (ret != len)) { 1112f1ae32a1SGerd Hoffmann /* Partial packet transfer: TD not ready to retire yet */ 1113f1ae32a1SGerd Hoffmann goto exit_no_retire; 1114f1ae32a1SGerd Hoffmann } 1115f1ae32a1SGerd Hoffmann 1116f1ae32a1SGerd Hoffmann /* Setting ED_C is part of the TD retirement process */ 1117f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_ED_C; 1118f1ae32a1SGerd Hoffmann if (td.flags & OHCI_TD_T0) 1119f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_C; 1120f1ae32a1SGerd Hoffmann } else { 1121f1ae32a1SGerd Hoffmann if (ret >= 0) { 1122dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_underrun(); 1123f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); 1124f1ae32a1SGerd Hoffmann } else { 1125f1ae32a1SGerd Hoffmann switch (ret) { 1126f1ae32a1SGerd Hoffmann case USB_RET_IOERROR: 1127f1ae32a1SGerd Hoffmann case USB_RET_NODEV: 1128dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_dev_error(); 1129f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); 11304b351a0fSJán Veselý break; 1131f1ae32a1SGerd Hoffmann case USB_RET_NAK: 1132dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_nak(); 1133f1ae32a1SGerd Hoffmann return 1; 1134f1ae32a1SGerd Hoffmann case USB_RET_STALL: 1135dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_stall(); 1136f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); 1137f1ae32a1SGerd Hoffmann break; 1138f1ae32a1SGerd Hoffmann case USB_RET_BABBLE: 1139dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_babble(); 1140f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); 1141f1ae32a1SGerd Hoffmann break; 1142f1ae32a1SGerd Hoffmann default: 1143dc1f5988SAlexey Kardashevskiy trace_usb_ohci_td_bad_device_response(ret); 1144f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); 1145f1ae32a1SGerd Hoffmann OHCI_SET_BM(td.flags, TD_EC, 3); 1146f1ae32a1SGerd Hoffmann break; 1147f1ae32a1SGerd Hoffmann } 1148f1ae32a1SGerd Hoffmann } 1149f1ae32a1SGerd Hoffmann ed->head |= OHCI_ED_H; 1150f1ae32a1SGerd Hoffmann } 1151f1ae32a1SGerd Hoffmann 1152f1ae32a1SGerd Hoffmann /* Retire this TD */ 1153f1ae32a1SGerd Hoffmann ed->head &= ~OHCI_DPTR_MASK; 1154f1ae32a1SGerd Hoffmann ed->head |= td.next & OHCI_DPTR_MASK; 1155f1ae32a1SGerd Hoffmann td.next = ohci->done; 1156f1ae32a1SGerd Hoffmann ohci->done = addr; 1157f1ae32a1SGerd Hoffmann i = OHCI_BM(td.flags, TD_DI); 1158f1ae32a1SGerd Hoffmann if (i < ohci->done_count) 1159f1ae32a1SGerd Hoffmann ohci->done_count = i; 1160f1ae32a1SGerd Hoffmann exit_no_retire: 1161cf66ee8eSAlexey Kardashevskiy if (ohci_put_td(ohci, addr, &td)) { 1162cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1163cf66ee8eSAlexey Kardashevskiy return 1; 1164cf66ee8eSAlexey Kardashevskiy } 1165f1ae32a1SGerd Hoffmann return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; 1166f1ae32a1SGerd Hoffmann } 1167f1ae32a1SGerd Hoffmann 1168f1ae32a1SGerd Hoffmann /* Service an endpoint list. Returns nonzero if active TD were found. */ 1169f1ae32a1SGerd Hoffmann static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) 1170f1ae32a1SGerd Hoffmann { 1171f1ae32a1SGerd Hoffmann struct ohci_ed ed; 1172f1ae32a1SGerd Hoffmann uint32_t next_ed; 1173f1ae32a1SGerd Hoffmann uint32_t cur; 1174f1ae32a1SGerd Hoffmann int active; 1175f1ae32a1SGerd Hoffmann 1176f1ae32a1SGerd Hoffmann active = 0; 1177f1ae32a1SGerd Hoffmann 1178f1ae32a1SGerd Hoffmann if (head == 0) 1179f1ae32a1SGerd Hoffmann return 0; 1180f1ae32a1SGerd Hoffmann 1181f1ae32a1SGerd Hoffmann for (cur = head; cur; cur = next_ed) { 1182cf66ee8eSAlexey Kardashevskiy if (ohci_read_ed(ohci, cur, &ed)) { 1183dc1f5988SAlexey Kardashevskiy trace_usb_ohci_ed_read_error(cur); 1184cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1185f1ae32a1SGerd Hoffmann return 0; 1186f1ae32a1SGerd Hoffmann } 1187f1ae32a1SGerd Hoffmann 1188f1ae32a1SGerd Hoffmann next_ed = ed.next & OHCI_DPTR_MASK; 1189f1ae32a1SGerd Hoffmann 1190f1ae32a1SGerd Hoffmann if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) { 1191f1ae32a1SGerd Hoffmann uint32_t addr; 1192f1ae32a1SGerd Hoffmann /* Cancel pending packets for ED that have been paused. */ 1193f1ae32a1SGerd Hoffmann addr = ed.head & OHCI_DPTR_MASK; 1194f1ae32a1SGerd Hoffmann if (ohci->async_td && addr == ohci->async_td) { 1195f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1196f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1197f79738b0SHans de Goede usb_device_ep_stopped(ohci->usb_packet.ep->dev, 1198f79738b0SHans de Goede ohci->usb_packet.ep); 1199f1ae32a1SGerd Hoffmann } 1200f1ae32a1SGerd Hoffmann continue; 1201f1ae32a1SGerd Hoffmann } 1202f1ae32a1SGerd Hoffmann 1203f1ae32a1SGerd Hoffmann while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { 12043af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0, 12053af8f177SAlexey Kardashevskiy (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, 12063af8f177SAlexey Kardashevskiy ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); 12073af8f177SAlexey Kardashevskiy trace_usb_ohci_ed_pkt_flags( 1208f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), 1209f1ae32a1SGerd Hoffmann OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, 1210f1ae32a1SGerd Hoffmann (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, 12113af8f177SAlexey Kardashevskiy OHCI_BM(ed.flags, ED_MPS)); 1212dc1f5988SAlexey Kardashevskiy 1213f1ae32a1SGerd Hoffmann active = 1; 1214f1ae32a1SGerd Hoffmann 1215f1ae32a1SGerd Hoffmann if ((ed.flags & OHCI_ED_F) == 0) { 1216f1ae32a1SGerd Hoffmann if (ohci_service_td(ohci, &ed)) 1217f1ae32a1SGerd Hoffmann break; 1218f1ae32a1SGerd Hoffmann } else { 1219f1ae32a1SGerd Hoffmann /* Handle isochronous endpoints */ 1220f1ae32a1SGerd Hoffmann if (ohci_service_iso_td(ohci, &ed, completion)) 1221f1ae32a1SGerd Hoffmann break; 1222f1ae32a1SGerd Hoffmann } 1223f1ae32a1SGerd Hoffmann } 1224f1ae32a1SGerd Hoffmann 1225cf66ee8eSAlexey Kardashevskiy if (ohci_put_ed(ohci, cur, &ed)) { 1226cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1227cf66ee8eSAlexey Kardashevskiy return 0; 1228cf66ee8eSAlexey Kardashevskiy } 1229f1ae32a1SGerd Hoffmann } 1230f1ae32a1SGerd Hoffmann 1231f1ae32a1SGerd Hoffmann return active; 1232f1ae32a1SGerd Hoffmann } 1233f1ae32a1SGerd Hoffmann 1234f1ae32a1SGerd Hoffmann /* Generate a SOF event, and set a timer for EOF */ 1235f1ae32a1SGerd Hoffmann static void ohci_sof(OHCIState *ohci) 1236f1ae32a1SGerd Hoffmann { 1237bc72ad67SAlex Bligh ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1238bc72ad67SAlex Bligh timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time); 1239f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_SF); 1240f1ae32a1SGerd Hoffmann } 1241f1ae32a1SGerd Hoffmann 1242f1ae32a1SGerd Hoffmann /* Process Control and Bulk lists. */ 1243f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion) 1244f1ae32a1SGerd Hoffmann { 1245f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { 1246f1ae32a1SGerd Hoffmann if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) { 1247dc1f5988SAlexey Kardashevskiy trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur); 1248f1ae32a1SGerd Hoffmann } 1249f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) { 1250f1ae32a1SGerd Hoffmann ohci->ctrl_cur = 0; 1251f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_CLF; 1252f1ae32a1SGerd Hoffmann } 1253f1ae32a1SGerd Hoffmann } 1254f1ae32a1SGerd Hoffmann 1255f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { 1256f1ae32a1SGerd Hoffmann if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) { 1257f1ae32a1SGerd Hoffmann ohci->bulk_cur = 0; 1258f1ae32a1SGerd Hoffmann ohci->status &= ~OHCI_STATUS_BLF; 1259f1ae32a1SGerd Hoffmann } 1260f1ae32a1SGerd Hoffmann } 1261f1ae32a1SGerd Hoffmann } 1262f1ae32a1SGerd Hoffmann 1263f1ae32a1SGerd Hoffmann /* Do frame processing on frame boundary */ 1264f1ae32a1SGerd Hoffmann static void ohci_frame_boundary(void *opaque) 1265f1ae32a1SGerd Hoffmann { 1266f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1267f1ae32a1SGerd Hoffmann struct ohci_hcca hcca; 1268f1ae32a1SGerd Hoffmann 1269cf66ee8eSAlexey Kardashevskiy if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) { 1270dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hcca_read_error(ohci->hcca); 1271cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1272cf66ee8eSAlexey Kardashevskiy return; 1273cf66ee8eSAlexey Kardashevskiy } 1274f1ae32a1SGerd Hoffmann 1275f1ae32a1SGerd Hoffmann /* Process all the lists at the end of the frame */ 1276f1ae32a1SGerd Hoffmann if (ohci->ctl & OHCI_CTL_PLE) { 1277f1ae32a1SGerd Hoffmann int n; 1278f1ae32a1SGerd Hoffmann 1279f1ae32a1SGerd Hoffmann n = ohci->frame_number & 0x1f; 1280f1ae32a1SGerd Hoffmann ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0); 1281f1ae32a1SGerd Hoffmann } 1282f1ae32a1SGerd Hoffmann 1283f1ae32a1SGerd Hoffmann /* Cancel all pending packets if either of the lists has been disabled. */ 1284f79738b0SHans de Goede if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { 1285f79738b0SHans de Goede if (ohci->async_td) { 1286f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1287f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1288f1ae32a1SGerd Hoffmann } 1289f79738b0SHans de Goede ohci_stop_endpoints(ohci); 1290f79738b0SHans de Goede } 1291f1ae32a1SGerd Hoffmann ohci->old_ctl = ohci->ctl; 1292f1ae32a1SGerd Hoffmann ohci_process_lists(ohci, 0); 1293f1ae32a1SGerd Hoffmann 1294cf66ee8eSAlexey Kardashevskiy /* Stop if UnrecoverableError happened or ohci_sof will crash */ 1295cf66ee8eSAlexey Kardashevskiy if (ohci->intr_status & OHCI_INTR_UE) { 1296cf66ee8eSAlexey Kardashevskiy return; 1297cf66ee8eSAlexey Kardashevskiy } 1298cf66ee8eSAlexey Kardashevskiy 1299f1ae32a1SGerd Hoffmann /* Frame boundary, so do EOF stuf here */ 1300f1ae32a1SGerd Hoffmann ohci->frt = ohci->fit; 1301f1ae32a1SGerd Hoffmann 1302f1ae32a1SGerd Hoffmann /* Increment frame number and take care of endianness. */ 1303f1ae32a1SGerd Hoffmann ohci->frame_number = (ohci->frame_number + 1) & 0xffff; 1304f1ae32a1SGerd Hoffmann hcca.frame = cpu_to_le16(ohci->frame_number); 1305f1ae32a1SGerd Hoffmann 1306f1ae32a1SGerd Hoffmann if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { 1307f1ae32a1SGerd Hoffmann if (!ohci->done) 1308f1ae32a1SGerd Hoffmann abort(); 1309f1ae32a1SGerd Hoffmann if (ohci->intr & ohci->intr_status) 1310f1ae32a1SGerd Hoffmann ohci->done |= 1; 1311f1ae32a1SGerd Hoffmann hcca.done = cpu_to_le32(ohci->done); 1312f1ae32a1SGerd Hoffmann ohci->done = 0; 1313f1ae32a1SGerd Hoffmann ohci->done_count = 7; 1314f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_WD); 1315f1ae32a1SGerd Hoffmann } 1316f1ae32a1SGerd Hoffmann 1317f1ae32a1SGerd Hoffmann if (ohci->done_count != 7 && ohci->done_count != 0) 1318f1ae32a1SGerd Hoffmann ohci->done_count--; 1319f1ae32a1SGerd Hoffmann 1320f1ae32a1SGerd Hoffmann /* Do SOF stuff here */ 1321f1ae32a1SGerd Hoffmann ohci_sof(ohci); 1322f1ae32a1SGerd Hoffmann 1323f1ae32a1SGerd Hoffmann /* Writeback HCCA */ 1324cf66ee8eSAlexey Kardashevskiy if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) { 1325cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1326cf66ee8eSAlexey Kardashevskiy } 1327f1ae32a1SGerd Hoffmann } 1328f1ae32a1SGerd Hoffmann 1329f1ae32a1SGerd Hoffmann /* Start sending SOF tokens across the USB bus, lists are processed in 1330f1ae32a1SGerd Hoffmann * next frame 1331f1ae32a1SGerd Hoffmann */ 1332f1ae32a1SGerd Hoffmann static int ohci_bus_start(OHCIState *ohci) 1333f1ae32a1SGerd Hoffmann { 1334bc72ad67SAlex Bligh ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1335f1ae32a1SGerd Hoffmann ohci_frame_boundary, 1336f1ae32a1SGerd Hoffmann ohci); 1337f1ae32a1SGerd Hoffmann 1338f1ae32a1SGerd Hoffmann if (ohci->eof_timer == NULL) { 1339dc1f5988SAlexey Kardashevskiy trace_usb_ohci_bus_eof_timer_failed(ohci->name); 1340cf66ee8eSAlexey Kardashevskiy ohci_die(ohci); 1341f1ae32a1SGerd Hoffmann return 0; 1342f1ae32a1SGerd Hoffmann } 1343f1ae32a1SGerd Hoffmann 1344dc1f5988SAlexey Kardashevskiy trace_usb_ohci_start(ohci->name); 1345f1ae32a1SGerd Hoffmann 1346f1ae32a1SGerd Hoffmann ohci_sof(ohci); 1347f1ae32a1SGerd Hoffmann 1348f1ae32a1SGerd Hoffmann return 1; 1349f1ae32a1SGerd Hoffmann } 1350f1ae32a1SGerd Hoffmann 1351f1ae32a1SGerd Hoffmann /* Stop sending SOF tokens on the bus */ 1352f1ae32a1SGerd Hoffmann static void ohci_bus_stop(OHCIState *ohci) 1353f1ae32a1SGerd Hoffmann { 1354dc1f5988SAlexey Kardashevskiy trace_usb_ohci_stop(ohci->name); 135580be63dfSGonglei if (ohci->eof_timer) { 1356bc72ad67SAlex Bligh timer_del(ohci->eof_timer); 135780be63dfSGonglei timer_free(ohci->eof_timer); 135880be63dfSGonglei } 1359f1ae32a1SGerd Hoffmann ohci->eof_timer = NULL; 1360f1ae32a1SGerd Hoffmann } 1361f1ae32a1SGerd Hoffmann 1362f1ae32a1SGerd Hoffmann /* Sets a flag in a port status register but only set it if the port is 1363f1ae32a1SGerd Hoffmann * connected, if not set ConnectStatusChange flag. If flag is enabled 1364f1ae32a1SGerd Hoffmann * return 1. 1365f1ae32a1SGerd Hoffmann */ 1366f1ae32a1SGerd Hoffmann static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) 1367f1ae32a1SGerd Hoffmann { 1368f1ae32a1SGerd Hoffmann int ret = 1; 1369f1ae32a1SGerd Hoffmann 1370f1ae32a1SGerd Hoffmann /* writing a 0 has no effect */ 1371f1ae32a1SGerd Hoffmann if (val == 0) 1372f1ae32a1SGerd Hoffmann return 0; 1373f1ae32a1SGerd Hoffmann 1374f1ae32a1SGerd Hoffmann /* If CurrentConnectStatus is cleared we set 1375f1ae32a1SGerd Hoffmann * ConnectStatusChange 1376f1ae32a1SGerd Hoffmann */ 1377f1ae32a1SGerd Hoffmann if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { 1378f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_CSC; 1379f1ae32a1SGerd Hoffmann if (ohci->rhstatus & OHCI_RHS_DRWE) { 1380f1ae32a1SGerd Hoffmann /* TODO: CSC is a wakeup event */ 1381f1ae32a1SGerd Hoffmann } 1382f1ae32a1SGerd Hoffmann return 0; 1383f1ae32a1SGerd Hoffmann } 1384f1ae32a1SGerd Hoffmann 1385f1ae32a1SGerd Hoffmann if (ohci->rhport[i].ctrl & val) 1386f1ae32a1SGerd Hoffmann ret = 0; 1387f1ae32a1SGerd Hoffmann 1388f1ae32a1SGerd Hoffmann /* set the bit */ 1389f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= val; 1390f1ae32a1SGerd Hoffmann 1391f1ae32a1SGerd Hoffmann return ret; 1392f1ae32a1SGerd Hoffmann } 1393f1ae32a1SGerd Hoffmann 1394f1ae32a1SGerd Hoffmann /* Set the frame interval - frame interval toggle is manipulated by the hcd only */ 1395f1ae32a1SGerd Hoffmann static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) 1396f1ae32a1SGerd Hoffmann { 1397f1ae32a1SGerd Hoffmann val &= OHCI_FMI_FI; 1398f1ae32a1SGerd Hoffmann 1399f1ae32a1SGerd Hoffmann if (val != ohci->fi) { 1400dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi); 1401f1ae32a1SGerd Hoffmann } 1402f1ae32a1SGerd Hoffmann 1403f1ae32a1SGerd Hoffmann ohci->fi = val; 1404f1ae32a1SGerd Hoffmann } 1405f1ae32a1SGerd Hoffmann 1406f1ae32a1SGerd Hoffmann static void ohci_port_power(OHCIState *ohci, int i, int p) 1407f1ae32a1SGerd Hoffmann { 1408f1ae32a1SGerd Hoffmann if (p) { 1409f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl |= OHCI_PORT_PPS; 1410f1ae32a1SGerd Hoffmann } else { 1411f1ae32a1SGerd Hoffmann ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| 1412f1ae32a1SGerd Hoffmann OHCI_PORT_CCS| 1413f1ae32a1SGerd Hoffmann OHCI_PORT_PSS| 1414f1ae32a1SGerd Hoffmann OHCI_PORT_PRS); 1415f1ae32a1SGerd Hoffmann } 1416f1ae32a1SGerd Hoffmann } 1417f1ae32a1SGerd Hoffmann 1418f1ae32a1SGerd Hoffmann /* Set HcControlRegister */ 1419f1ae32a1SGerd Hoffmann static void ohci_set_ctl(OHCIState *ohci, uint32_t val) 1420f1ae32a1SGerd Hoffmann { 1421f1ae32a1SGerd Hoffmann uint32_t old_state; 1422f1ae32a1SGerd Hoffmann uint32_t new_state; 1423f1ae32a1SGerd Hoffmann 1424f1ae32a1SGerd Hoffmann old_state = ohci->ctl & OHCI_CTL_HCFS; 1425f1ae32a1SGerd Hoffmann ohci->ctl = val; 1426f1ae32a1SGerd Hoffmann new_state = ohci->ctl & OHCI_CTL_HCFS; 1427f1ae32a1SGerd Hoffmann 1428f1ae32a1SGerd Hoffmann /* no state change */ 1429f1ae32a1SGerd Hoffmann if (old_state == new_state) 1430f1ae32a1SGerd Hoffmann return; 1431f1ae32a1SGerd Hoffmann 1432dc1f5988SAlexey Kardashevskiy trace_usb_ohci_set_ctl(ohci->name, new_state); 1433f1ae32a1SGerd Hoffmann switch (new_state) { 1434f1ae32a1SGerd Hoffmann case OHCI_USB_OPERATIONAL: 1435f1ae32a1SGerd Hoffmann ohci_bus_start(ohci); 1436f1ae32a1SGerd Hoffmann break; 1437f1ae32a1SGerd Hoffmann case OHCI_USB_SUSPEND: 1438f1ae32a1SGerd Hoffmann ohci_bus_stop(ohci); 1439f1ae32a1SGerd Hoffmann break; 1440f1ae32a1SGerd Hoffmann case OHCI_USB_RESUME: 1441dc1f5988SAlexey Kardashevskiy trace_usb_ohci_resume(ohci->name); 1442f1ae32a1SGerd Hoffmann break; 1443f1ae32a1SGerd Hoffmann case OHCI_USB_RESET: 1444f1ae32a1SGerd Hoffmann ohci_reset(ohci); 1445f1ae32a1SGerd Hoffmann break; 1446f1ae32a1SGerd Hoffmann } 1447f1ae32a1SGerd Hoffmann } 1448f1ae32a1SGerd Hoffmann 1449f1ae32a1SGerd Hoffmann static uint32_t ohci_get_frame_remaining(OHCIState *ohci) 1450f1ae32a1SGerd Hoffmann { 1451f1ae32a1SGerd Hoffmann uint16_t fr; 1452f1ae32a1SGerd Hoffmann int64_t tks; 1453f1ae32a1SGerd Hoffmann 1454f1ae32a1SGerd Hoffmann if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) 1455f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1456f1ae32a1SGerd Hoffmann 1457f1ae32a1SGerd Hoffmann /* Being in USB operational state guarnatees sof_time was 1458f1ae32a1SGerd Hoffmann * set already. 1459f1ae32a1SGerd Hoffmann */ 1460bc72ad67SAlex Bligh tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time; 1461f1ae32a1SGerd Hoffmann 1462f1ae32a1SGerd Hoffmann /* avoid muldiv if possible */ 1463f1ae32a1SGerd Hoffmann if (tks >= usb_frame_time) 1464f1ae32a1SGerd Hoffmann return (ohci->frt << 31); 1465f1ae32a1SGerd Hoffmann 1466f1ae32a1SGerd Hoffmann tks = muldiv64(1, tks, usb_bit_time); 1467f1ae32a1SGerd Hoffmann fr = (uint16_t)(ohci->fi - tks); 1468f1ae32a1SGerd Hoffmann 1469f1ae32a1SGerd Hoffmann return (ohci->frt << 31) | fr; 1470f1ae32a1SGerd Hoffmann } 1471f1ae32a1SGerd Hoffmann 1472f1ae32a1SGerd Hoffmann 1473f1ae32a1SGerd Hoffmann /* Set root hub status */ 1474f1ae32a1SGerd Hoffmann static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) 1475f1ae32a1SGerd Hoffmann { 1476f1ae32a1SGerd Hoffmann uint32_t old_state; 1477f1ae32a1SGerd Hoffmann 1478f1ae32a1SGerd Hoffmann old_state = ohci->rhstatus; 1479f1ae32a1SGerd Hoffmann 1480f1ae32a1SGerd Hoffmann /* write 1 to clear OCIC */ 1481f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_OCIC) 1482f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_OCIC; 1483f1ae32a1SGerd Hoffmann 1484f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPS) { 1485f1ae32a1SGerd Hoffmann int i; 1486f1ae32a1SGerd Hoffmann 1487f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1488f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 0); 1489dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_down(); 1490f1ae32a1SGerd Hoffmann } 1491f1ae32a1SGerd Hoffmann 1492f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_LPSC) { 1493f1ae32a1SGerd Hoffmann int i; 1494f1ae32a1SGerd Hoffmann 1495f1ae32a1SGerd Hoffmann for (i = 0; i < ohci->num_ports; i++) 1496f1ae32a1SGerd Hoffmann ohci_port_power(ohci, i, 1); 1497dc1f5988SAlexey Kardashevskiy trace_usb_ohci_hub_power_up(); 1498f1ae32a1SGerd Hoffmann } 1499f1ae32a1SGerd Hoffmann 1500f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_DRWE) 1501f1ae32a1SGerd Hoffmann ohci->rhstatus |= OHCI_RHS_DRWE; 1502f1ae32a1SGerd Hoffmann 1503f1ae32a1SGerd Hoffmann if (val & OHCI_RHS_CRWE) 1504f1ae32a1SGerd Hoffmann ohci->rhstatus &= ~OHCI_RHS_DRWE; 1505f1ae32a1SGerd Hoffmann 1506f1ae32a1SGerd Hoffmann if (old_state != ohci->rhstatus) 1507f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1508f1ae32a1SGerd Hoffmann } 1509f1ae32a1SGerd Hoffmann 1510f1ae32a1SGerd Hoffmann /* Set root hub port status */ 1511f1ae32a1SGerd Hoffmann static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) 1512f1ae32a1SGerd Hoffmann { 1513f1ae32a1SGerd Hoffmann uint32_t old_state; 1514f1ae32a1SGerd Hoffmann OHCIPort *port; 1515f1ae32a1SGerd Hoffmann 1516f1ae32a1SGerd Hoffmann port = &ohci->rhport[portnum]; 1517f1ae32a1SGerd Hoffmann old_state = port->ctrl; 1518f1ae32a1SGerd Hoffmann 1519f1ae32a1SGerd Hoffmann /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ 1520f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_WTC) 1521f1ae32a1SGerd Hoffmann port->ctrl &= ~(val & OHCI_PORT_WTC); 1522f1ae32a1SGerd Hoffmann 1523f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_CCS) 1524f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PES; 1525f1ae32a1SGerd Hoffmann 1526f1ae32a1SGerd Hoffmann ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); 1527f1ae32a1SGerd Hoffmann 1528f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) { 1529dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_suspend(portnum); 1530f1ae32a1SGerd Hoffmann } 1531f1ae32a1SGerd Hoffmann 1532f1ae32a1SGerd Hoffmann if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { 1533dc1f5988SAlexey Kardashevskiy trace_usb_ohci_port_reset(portnum); 1534f1ae32a1SGerd Hoffmann usb_device_reset(port->port.dev); 1535f1ae32a1SGerd Hoffmann port->ctrl &= ~OHCI_PORT_PRS; 1536f1ae32a1SGerd Hoffmann /* ??? Should this also set OHCI_PORT_PESC. */ 1537f1ae32a1SGerd Hoffmann port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; 1538f1ae32a1SGerd Hoffmann } 1539f1ae32a1SGerd Hoffmann 1540f1ae32a1SGerd Hoffmann /* Invert order here to ensure in ambiguous case, device is 1541f1ae32a1SGerd Hoffmann * powered up... 1542f1ae32a1SGerd Hoffmann */ 1543f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_LSDA) 1544f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 0); 1545f1ae32a1SGerd Hoffmann if (val & OHCI_PORT_PPS) 1546f1ae32a1SGerd Hoffmann ohci_port_power(ohci, portnum, 1); 1547f1ae32a1SGerd Hoffmann 1548f1ae32a1SGerd Hoffmann if (old_state != port->ctrl) 1549f1ae32a1SGerd Hoffmann ohci_set_interrupt(ohci, OHCI_INTR_RHSC); 1550f1ae32a1SGerd Hoffmann } 1551f1ae32a1SGerd Hoffmann 1552f1ae32a1SGerd Hoffmann static uint64_t ohci_mem_read(void *opaque, 1553a8170e5eSAvi Kivity hwaddr addr, 1554f1ae32a1SGerd Hoffmann unsigned size) 1555f1ae32a1SGerd Hoffmann { 1556f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1557f1ae32a1SGerd Hoffmann uint32_t retval; 1558f1ae32a1SGerd Hoffmann 1559f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1560f1ae32a1SGerd Hoffmann if (addr & 3) { 1561dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_unaligned(addr); 1562f1ae32a1SGerd Hoffmann return 0xffffffff; 1563f1ae32a1SGerd Hoffmann } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1564f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1565f1ae32a1SGerd Hoffmann retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; 1566f1ae32a1SGerd Hoffmann } else { 1567f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1568f1ae32a1SGerd Hoffmann case 0: /* HcRevision */ 1569f1ae32a1SGerd Hoffmann retval = 0x10; 1570f1ae32a1SGerd Hoffmann break; 1571f1ae32a1SGerd Hoffmann 1572f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1573f1ae32a1SGerd Hoffmann retval = ohci->ctl; 1574f1ae32a1SGerd Hoffmann break; 1575f1ae32a1SGerd Hoffmann 1576f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1577f1ae32a1SGerd Hoffmann retval = ohci->status; 1578f1ae32a1SGerd Hoffmann break; 1579f1ae32a1SGerd Hoffmann 1580f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1581f1ae32a1SGerd Hoffmann retval = ohci->intr_status; 1582f1ae32a1SGerd Hoffmann break; 1583f1ae32a1SGerd Hoffmann 1584f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1585f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1586f1ae32a1SGerd Hoffmann retval = ohci->intr; 1587f1ae32a1SGerd Hoffmann break; 1588f1ae32a1SGerd Hoffmann 1589f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1590f1ae32a1SGerd Hoffmann retval = ohci->hcca; 1591f1ae32a1SGerd Hoffmann break; 1592f1ae32a1SGerd Hoffmann 1593f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1594f1ae32a1SGerd Hoffmann retval = ohci->per_cur; 1595f1ae32a1SGerd Hoffmann break; 1596f1ae32a1SGerd Hoffmann 1597f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1598f1ae32a1SGerd Hoffmann retval = ohci->ctrl_head; 1599f1ae32a1SGerd Hoffmann break; 1600f1ae32a1SGerd Hoffmann 1601f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1602f1ae32a1SGerd Hoffmann retval = ohci->ctrl_cur; 1603f1ae32a1SGerd Hoffmann break; 1604f1ae32a1SGerd Hoffmann 1605f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1606f1ae32a1SGerd Hoffmann retval = ohci->bulk_head; 1607f1ae32a1SGerd Hoffmann break; 1608f1ae32a1SGerd Hoffmann 1609f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1610f1ae32a1SGerd Hoffmann retval = ohci->bulk_cur; 1611f1ae32a1SGerd Hoffmann break; 1612f1ae32a1SGerd Hoffmann 1613f1ae32a1SGerd Hoffmann case 12: /* HcDoneHead */ 1614f1ae32a1SGerd Hoffmann retval = ohci->done; 1615f1ae32a1SGerd Hoffmann break; 1616f1ae32a1SGerd Hoffmann 1617f1ae32a1SGerd Hoffmann case 13: /* HcFmInterretval */ 1618f1ae32a1SGerd Hoffmann retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); 1619f1ae32a1SGerd Hoffmann break; 1620f1ae32a1SGerd Hoffmann 1621f1ae32a1SGerd Hoffmann case 14: /* HcFmRemaining */ 1622f1ae32a1SGerd Hoffmann retval = ohci_get_frame_remaining(ohci); 1623f1ae32a1SGerd Hoffmann break; 1624f1ae32a1SGerd Hoffmann 1625f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1626f1ae32a1SGerd Hoffmann retval = ohci->frame_number; 1627f1ae32a1SGerd Hoffmann break; 1628f1ae32a1SGerd Hoffmann 1629f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1630f1ae32a1SGerd Hoffmann retval = ohci->pstart; 1631f1ae32a1SGerd Hoffmann break; 1632f1ae32a1SGerd Hoffmann 1633f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1634f1ae32a1SGerd Hoffmann retval = ohci->lst; 1635f1ae32a1SGerd Hoffmann break; 1636f1ae32a1SGerd Hoffmann 1637f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1638f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_a; 1639f1ae32a1SGerd Hoffmann break; 1640f1ae32a1SGerd Hoffmann 1641f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1642f1ae32a1SGerd Hoffmann retval = ohci->rhdesc_b; 1643f1ae32a1SGerd Hoffmann break; 1644f1ae32a1SGerd Hoffmann 1645f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1646f1ae32a1SGerd Hoffmann retval = ohci->rhstatus; 1647f1ae32a1SGerd Hoffmann break; 1648f1ae32a1SGerd Hoffmann 1649f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1650f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1651f1ae32a1SGerd Hoffmann retval = ohci->hstatus & ohci->hmask; 1652f1ae32a1SGerd Hoffmann break; 1653f1ae32a1SGerd Hoffmann 1654f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1655f1ae32a1SGerd Hoffmann retval = ohci->hreset; 1656f1ae32a1SGerd Hoffmann break; 1657f1ae32a1SGerd Hoffmann 1658f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1659f1ae32a1SGerd Hoffmann retval = ohci->hmask; 1660f1ae32a1SGerd Hoffmann break; 1661f1ae32a1SGerd Hoffmann 1662f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1663f1ae32a1SGerd Hoffmann retval = ohci->htest; 1664f1ae32a1SGerd Hoffmann break; 1665f1ae32a1SGerd Hoffmann 1666f1ae32a1SGerd Hoffmann default: 1667dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_read_bad_offset(addr); 1668f1ae32a1SGerd Hoffmann retval = 0xffffffff; 1669f1ae32a1SGerd Hoffmann } 1670f1ae32a1SGerd Hoffmann } 1671f1ae32a1SGerd Hoffmann 1672f1ae32a1SGerd Hoffmann return retval; 1673f1ae32a1SGerd Hoffmann } 1674f1ae32a1SGerd Hoffmann 1675f1ae32a1SGerd Hoffmann static void ohci_mem_write(void *opaque, 1676a8170e5eSAvi Kivity hwaddr addr, 1677f1ae32a1SGerd Hoffmann uint64_t val, 1678f1ae32a1SGerd Hoffmann unsigned size) 1679f1ae32a1SGerd Hoffmann { 1680f1ae32a1SGerd Hoffmann OHCIState *ohci = opaque; 1681f1ae32a1SGerd Hoffmann 1682f1ae32a1SGerd Hoffmann /* Only aligned reads are allowed on OHCI */ 1683f1ae32a1SGerd Hoffmann if (addr & 3) { 1684dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_unaligned(addr); 1685f1ae32a1SGerd Hoffmann return; 1686f1ae32a1SGerd Hoffmann } 1687f1ae32a1SGerd Hoffmann 1688f1ae32a1SGerd Hoffmann if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { 1689f1ae32a1SGerd Hoffmann /* HcRhPortStatus */ 1690f1ae32a1SGerd Hoffmann ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); 1691f1ae32a1SGerd Hoffmann return; 1692f1ae32a1SGerd Hoffmann } 1693f1ae32a1SGerd Hoffmann 1694f1ae32a1SGerd Hoffmann switch (addr >> 2) { 1695f1ae32a1SGerd Hoffmann case 1: /* HcControl */ 1696f1ae32a1SGerd Hoffmann ohci_set_ctl(ohci, val); 1697f1ae32a1SGerd Hoffmann break; 1698f1ae32a1SGerd Hoffmann 1699f1ae32a1SGerd Hoffmann case 2: /* HcCommandStatus */ 1700f1ae32a1SGerd Hoffmann /* SOC is read-only */ 1701f1ae32a1SGerd Hoffmann val = (val & ~OHCI_STATUS_SOC); 1702f1ae32a1SGerd Hoffmann 1703f1ae32a1SGerd Hoffmann /* Bits written as '0' remain unchanged in the register */ 1704f1ae32a1SGerd Hoffmann ohci->status |= val; 1705f1ae32a1SGerd Hoffmann 1706f1ae32a1SGerd Hoffmann if (ohci->status & OHCI_STATUS_HCR) 1707f1ae32a1SGerd Hoffmann ohci_reset(ohci); 1708f1ae32a1SGerd Hoffmann break; 1709f1ae32a1SGerd Hoffmann 1710f1ae32a1SGerd Hoffmann case 3: /* HcInterruptStatus */ 1711f1ae32a1SGerd Hoffmann ohci->intr_status &= ~val; 1712f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1713f1ae32a1SGerd Hoffmann break; 1714f1ae32a1SGerd Hoffmann 1715f1ae32a1SGerd Hoffmann case 4: /* HcInterruptEnable */ 1716f1ae32a1SGerd Hoffmann ohci->intr |= val; 1717f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1718f1ae32a1SGerd Hoffmann break; 1719f1ae32a1SGerd Hoffmann 1720f1ae32a1SGerd Hoffmann case 5: /* HcInterruptDisable */ 1721f1ae32a1SGerd Hoffmann ohci->intr &= ~val; 1722f1ae32a1SGerd Hoffmann ohci_intr_update(ohci); 1723f1ae32a1SGerd Hoffmann break; 1724f1ae32a1SGerd Hoffmann 1725f1ae32a1SGerd Hoffmann case 6: /* HcHCCA */ 1726f1ae32a1SGerd Hoffmann ohci->hcca = val & OHCI_HCCA_MASK; 1727f1ae32a1SGerd Hoffmann break; 1728f1ae32a1SGerd Hoffmann 1729f1ae32a1SGerd Hoffmann case 7: /* HcPeriodCurrentED */ 1730f1ae32a1SGerd Hoffmann /* Ignore writes to this read-only register, Linux does them */ 1731f1ae32a1SGerd Hoffmann break; 1732f1ae32a1SGerd Hoffmann 1733f1ae32a1SGerd Hoffmann case 8: /* HcControlHeadED */ 1734f1ae32a1SGerd Hoffmann ohci->ctrl_head = val & OHCI_EDPTR_MASK; 1735f1ae32a1SGerd Hoffmann break; 1736f1ae32a1SGerd Hoffmann 1737f1ae32a1SGerd Hoffmann case 9: /* HcControlCurrentED */ 1738f1ae32a1SGerd Hoffmann ohci->ctrl_cur = val & OHCI_EDPTR_MASK; 1739f1ae32a1SGerd Hoffmann break; 1740f1ae32a1SGerd Hoffmann 1741f1ae32a1SGerd Hoffmann case 10: /* HcBulkHeadED */ 1742f1ae32a1SGerd Hoffmann ohci->bulk_head = val & OHCI_EDPTR_MASK; 1743f1ae32a1SGerd Hoffmann break; 1744f1ae32a1SGerd Hoffmann 1745f1ae32a1SGerd Hoffmann case 11: /* HcBulkCurrentED */ 1746f1ae32a1SGerd Hoffmann ohci->bulk_cur = val & OHCI_EDPTR_MASK; 1747f1ae32a1SGerd Hoffmann break; 1748f1ae32a1SGerd Hoffmann 1749f1ae32a1SGerd Hoffmann case 13: /* HcFmInterval */ 1750f1ae32a1SGerd Hoffmann ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; 1751f1ae32a1SGerd Hoffmann ohci->fit = (val & OHCI_FMI_FIT) >> 31; 1752f1ae32a1SGerd Hoffmann ohci_set_frame_interval(ohci, val); 1753f1ae32a1SGerd Hoffmann break; 1754f1ae32a1SGerd Hoffmann 1755f1ae32a1SGerd Hoffmann case 15: /* HcFmNumber */ 1756f1ae32a1SGerd Hoffmann break; 1757f1ae32a1SGerd Hoffmann 1758f1ae32a1SGerd Hoffmann case 16: /* HcPeriodicStart */ 1759f1ae32a1SGerd Hoffmann ohci->pstart = val & 0xffff; 1760f1ae32a1SGerd Hoffmann break; 1761f1ae32a1SGerd Hoffmann 1762f1ae32a1SGerd Hoffmann case 17: /* HcLSThreshold */ 1763f1ae32a1SGerd Hoffmann ohci->lst = val & 0xffff; 1764f1ae32a1SGerd Hoffmann break; 1765f1ae32a1SGerd Hoffmann 1766f1ae32a1SGerd Hoffmann case 18: /* HcRhDescriptorA */ 1767f1ae32a1SGerd Hoffmann ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; 1768f1ae32a1SGerd Hoffmann ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; 1769f1ae32a1SGerd Hoffmann break; 1770f1ae32a1SGerd Hoffmann 1771f1ae32a1SGerd Hoffmann case 19: /* HcRhDescriptorB */ 1772f1ae32a1SGerd Hoffmann break; 1773f1ae32a1SGerd Hoffmann 1774f1ae32a1SGerd Hoffmann case 20: /* HcRhStatus */ 1775f1ae32a1SGerd Hoffmann ohci_set_hub_status(ohci, val); 1776f1ae32a1SGerd Hoffmann break; 1777f1ae32a1SGerd Hoffmann 1778f1ae32a1SGerd Hoffmann /* PXA27x specific registers */ 1779f1ae32a1SGerd Hoffmann case 24: /* HcStatus */ 1780f1ae32a1SGerd Hoffmann ohci->hstatus &= ~(val & ohci->hmask); 17817fa96d73SGerd Hoffmann break; 1782f1ae32a1SGerd Hoffmann 1783f1ae32a1SGerd Hoffmann case 25: /* HcHReset */ 1784f1ae32a1SGerd Hoffmann ohci->hreset = val & ~OHCI_HRESET_FSBIR; 1785f1ae32a1SGerd Hoffmann if (val & OHCI_HRESET_FSBIR) 1786f1ae32a1SGerd Hoffmann ohci_reset(ohci); 1787f1ae32a1SGerd Hoffmann break; 1788f1ae32a1SGerd Hoffmann 1789f1ae32a1SGerd Hoffmann case 26: /* HcHInterruptEnable */ 1790f1ae32a1SGerd Hoffmann ohci->hmask = val; 1791f1ae32a1SGerd Hoffmann break; 1792f1ae32a1SGerd Hoffmann 1793f1ae32a1SGerd Hoffmann case 27: /* HcHInterruptTest */ 1794f1ae32a1SGerd Hoffmann ohci->htest = val; 1795f1ae32a1SGerd Hoffmann break; 1796f1ae32a1SGerd Hoffmann 1797f1ae32a1SGerd Hoffmann default: 1798dc1f5988SAlexey Kardashevskiy trace_usb_ohci_mem_write_bad_offset(addr); 1799f1ae32a1SGerd Hoffmann break; 1800f1ae32a1SGerd Hoffmann } 1801f1ae32a1SGerd Hoffmann } 1802f1ae32a1SGerd Hoffmann 1803f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev) 1804f1ae32a1SGerd Hoffmann { 1805f1ae32a1SGerd Hoffmann if (ohci->async_td && 1806f1ae32a1SGerd Hoffmann usb_packet_is_inflight(&ohci->usb_packet) && 1807f1ae32a1SGerd Hoffmann ohci->usb_packet.ep->dev == dev) { 1808f1ae32a1SGerd Hoffmann usb_cancel_packet(&ohci->usb_packet); 1809f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1810f1ae32a1SGerd Hoffmann } 1811f1ae32a1SGerd Hoffmann } 1812f1ae32a1SGerd Hoffmann 1813f1ae32a1SGerd Hoffmann static const MemoryRegionOps ohci_mem_ops = { 1814f1ae32a1SGerd Hoffmann .read = ohci_mem_read, 1815f1ae32a1SGerd Hoffmann .write = ohci_mem_write, 1816f1ae32a1SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 1817f1ae32a1SGerd Hoffmann }; 1818f1ae32a1SGerd Hoffmann 1819f1ae32a1SGerd Hoffmann static USBPortOps ohci_port_ops = { 1820f1ae32a1SGerd Hoffmann .attach = ohci_attach, 1821f1ae32a1SGerd Hoffmann .detach = ohci_detach, 1822f1ae32a1SGerd Hoffmann .child_detach = ohci_child_detach, 1823f1ae32a1SGerd Hoffmann .wakeup = ohci_wakeup, 1824f1ae32a1SGerd Hoffmann .complete = ohci_async_complete_packet, 1825f1ae32a1SGerd Hoffmann }; 1826f1ae32a1SGerd Hoffmann 1827f1ae32a1SGerd Hoffmann static USBBusOps ohci_bus_ops = { 1828f1ae32a1SGerd Hoffmann }; 1829f1ae32a1SGerd Hoffmann 183087581feaSMarkus Armbruster static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, 18319ac6a217SDavid Gibson int num_ports, dma_addr_t localmem_base, 18329ac6a217SDavid Gibson char *masterbus, uint32_t firstport, 183387581feaSMarkus Armbruster AddressSpace *as, Error **errp) 1834f1ae32a1SGerd Hoffmann { 1835f4bbaaf5SMarkus Armbruster Error *err = NULL; 1836f1ae32a1SGerd Hoffmann int i; 1837f1ae32a1SGerd Hoffmann 1838df32fd1cSPaolo Bonzini ohci->as = as; 18399ac6a217SDavid Gibson 1840f1ae32a1SGerd Hoffmann if (usb_frame_time == 0) { 1841f1ae32a1SGerd Hoffmann #ifdef OHCI_TIME_WARP 1842f1ae32a1SGerd Hoffmann usb_frame_time = get_ticks_per_sec(); 1843f1ae32a1SGerd Hoffmann usb_bit_time = muldiv64(1, get_ticks_per_sec(), USB_HZ/1000); 1844f1ae32a1SGerd Hoffmann #else 1845f1ae32a1SGerd Hoffmann usb_frame_time = muldiv64(1, get_ticks_per_sec(), 1000); 1846f1ae32a1SGerd Hoffmann if (get_ticks_per_sec() >= USB_HZ) { 1847f1ae32a1SGerd Hoffmann usb_bit_time = muldiv64(1, get_ticks_per_sec(), USB_HZ); 1848f1ae32a1SGerd Hoffmann } else { 1849f1ae32a1SGerd Hoffmann usb_bit_time = 1; 1850f1ae32a1SGerd Hoffmann } 1851f1ae32a1SGerd Hoffmann #endif 1852dc1f5988SAlexey Kardashevskiy trace_usb_ohci_init_time(usb_frame_time, usb_bit_time); 1853f1ae32a1SGerd Hoffmann } 1854f1ae32a1SGerd Hoffmann 1855f1ae32a1SGerd Hoffmann ohci->num_ports = num_ports; 1856f1ae32a1SGerd Hoffmann if (masterbus) { 1857f1ae32a1SGerd Hoffmann USBPort *ports[OHCI_MAX_PORTS]; 1858f1ae32a1SGerd Hoffmann for(i = 0; i < num_ports; i++) { 1859f1ae32a1SGerd Hoffmann ports[i] = &ohci->rhport[i].port; 1860f1ae32a1SGerd Hoffmann } 1861f4bbaaf5SMarkus Armbruster usb_register_companion(masterbus, ports, num_ports, 1862f1ae32a1SGerd Hoffmann firstport, ohci, &ohci_port_ops, 1863f4bbaaf5SMarkus Armbruster USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, 1864f4bbaaf5SMarkus Armbruster &err); 1865f4bbaaf5SMarkus Armbruster if (err) { 186687581feaSMarkus Armbruster error_propagate(errp, err); 186787581feaSMarkus Armbruster return; 1868f1ae32a1SGerd Hoffmann } 1869f1ae32a1SGerd Hoffmann } else { 1870c889b3a5SAndreas Färber usb_bus_new(&ohci->bus, sizeof(ohci->bus), &ohci_bus_ops, dev); 1871f1ae32a1SGerd Hoffmann for (i = 0; i < num_ports; i++) { 1872f1ae32a1SGerd Hoffmann usb_register_port(&ohci->bus, &ohci->rhport[i].port, 1873f1ae32a1SGerd Hoffmann ohci, i, &ohci_port_ops, 1874f1ae32a1SGerd Hoffmann USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); 1875f1ae32a1SGerd Hoffmann } 1876f1ae32a1SGerd Hoffmann } 1877f1ae32a1SGerd Hoffmann 187822fc860bSPaolo Bonzini memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops, 187922fc860bSPaolo Bonzini ohci, "ohci", 256); 1880f1ae32a1SGerd Hoffmann ohci->localmem_base = localmem_base; 1881f1ae32a1SGerd Hoffmann 1882f1ae32a1SGerd Hoffmann ohci->name = object_get_typename(OBJECT(dev)); 1883f1ae32a1SGerd Hoffmann usb_packet_init(&ohci->usb_packet); 1884f1ae32a1SGerd Hoffmann 1885f1ae32a1SGerd Hoffmann ohci->async_td = 0; 1886f1ae32a1SGerd Hoffmann } 1887f1ae32a1SGerd Hoffmann 18881aa0c0c7SHu Tao #define TYPE_PCI_OHCI "pci-ohci" 18891aa0c0c7SHu Tao #define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) 18901aa0c0c7SHu Tao 1891f1ae32a1SGerd Hoffmann typedef struct { 18921aa0c0c7SHu Tao /*< private >*/ 18931aa0c0c7SHu Tao PCIDevice parent_obj; 18941aa0c0c7SHu Tao /*< public >*/ 18951aa0c0c7SHu Tao 1896f1ae32a1SGerd Hoffmann OHCIState state; 1897f1ae32a1SGerd Hoffmann char *masterbus; 1898f1ae32a1SGerd Hoffmann uint32_t num_ports; 1899f1ae32a1SGerd Hoffmann uint32_t firstport; 1900f1ae32a1SGerd Hoffmann } OHCIPCIState; 1901f1ae32a1SGerd Hoffmann 1902cf66ee8eSAlexey Kardashevskiy /** A typical O/EHCI will stop operating, set itself into error state 1903cf66ee8eSAlexey Kardashevskiy * (which can be queried by MMIO) and will set PERR in its config 1904cf66ee8eSAlexey Kardashevskiy * space to signal that it got an error 1905cf66ee8eSAlexey Kardashevskiy */ 1906cf66ee8eSAlexey Kardashevskiy static void ohci_die(OHCIState *ohci) 1907cf66ee8eSAlexey Kardashevskiy { 1908cf66ee8eSAlexey Kardashevskiy OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); 1909cf66ee8eSAlexey Kardashevskiy 1910dc1f5988SAlexey Kardashevskiy trace_usb_ohci_die(); 1911cf66ee8eSAlexey Kardashevskiy 1912cf66ee8eSAlexey Kardashevskiy ohci_set_interrupt(ohci, OHCI_INTR_UE); 1913cf66ee8eSAlexey Kardashevskiy ohci_bus_stop(ohci); 1914cf66ee8eSAlexey Kardashevskiy pci_set_word(dev->parent_obj.config + PCI_STATUS, 1915cf66ee8eSAlexey Kardashevskiy PCI_STATUS_DETECTED_PARITY); 1916cf66ee8eSAlexey Kardashevskiy } 1917cf66ee8eSAlexey Kardashevskiy 191887581feaSMarkus Armbruster static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp) 1919f1ae32a1SGerd Hoffmann { 192087581feaSMarkus Armbruster Error *err = NULL; 19211aa0c0c7SHu Tao OHCIPCIState *ohci = PCI_OHCI(dev); 1922f1ae32a1SGerd Hoffmann 19231aa0c0c7SHu Tao dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ 19241aa0c0c7SHu Tao dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ 1925f1ae32a1SGerd Hoffmann 192687581feaSMarkus Armbruster usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, 19279ac6a217SDavid Gibson ohci->masterbus, ohci->firstport, 192887581feaSMarkus Armbruster pci_get_address_space(dev), &err); 192987581feaSMarkus Armbruster if (err) { 193087581feaSMarkus Armbruster error_propagate(errp, err); 193187581feaSMarkus Armbruster return; 1932f1ae32a1SGerd Hoffmann } 1933f1ae32a1SGerd Hoffmann 193487581feaSMarkus Armbruster ohci->state.irq = pci_allocate_irq(dev); 19351aa0c0c7SHu Tao pci_register_bar(dev, 0, 0, &ohci->state.mem); 1936f1ae32a1SGerd Hoffmann } 1937f1ae32a1SGerd Hoffmann 193807832c38SGonglei static void usb_ohci_exit(PCIDevice *dev) 193907832c38SGonglei { 194007832c38SGonglei OHCIPCIState *ohci = PCI_OHCI(dev); 194107832c38SGonglei OHCIState *s = &ohci->state; 194207832c38SGonglei 1943dc1f5988SAlexey Kardashevskiy trace_usb_ohci_exit(s->name); 194407832c38SGonglei ohci_bus_stop(s); 194507832c38SGonglei 194607832c38SGonglei if (s->async_td) { 194707832c38SGonglei usb_cancel_packet(&s->usb_packet); 194807832c38SGonglei s->async_td = 0; 194907832c38SGonglei } 195007832c38SGonglei ohci_stop_endpoints(s); 195107832c38SGonglei 195207832c38SGonglei if (!ohci->masterbus) { 195307832c38SGonglei usb_bus_release(&s->bus); 195407832c38SGonglei } 195507832c38SGonglei } 195607832c38SGonglei 1957*88dd1b8dSGonglei static void usb_ohci_reset_pci(DeviceState *d) 1958*88dd1b8dSGonglei { 1959*88dd1b8dSGonglei PCIDevice *dev = PCI_DEVICE(d); 1960*88dd1b8dSGonglei OHCIPCIState *ohci = PCI_OHCI(dev); 1961*88dd1b8dSGonglei OHCIState *s = &ohci->state; 1962*88dd1b8dSGonglei 1963*88dd1b8dSGonglei ohci_reset(s); 1964*88dd1b8dSGonglei } 1965*88dd1b8dSGonglei 19661aa0c0c7SHu Tao #define TYPE_SYSBUS_OHCI "sysbus-ohci" 19671aa0c0c7SHu Tao #define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI) 19681aa0c0c7SHu Tao 1969f1ae32a1SGerd Hoffmann typedef struct { 19701aa0c0c7SHu Tao /*< private >*/ 19711aa0c0c7SHu Tao SysBusDevice parent_obj; 19721aa0c0c7SHu Tao /*< public >*/ 19731aa0c0c7SHu Tao 1974f1ae32a1SGerd Hoffmann OHCIState ohci; 1975f1ae32a1SGerd Hoffmann uint32_t num_ports; 19769ac6a217SDavid Gibson dma_addr_t dma_offset; 1977f1ae32a1SGerd Hoffmann } OHCISysBusState; 1978f1ae32a1SGerd Hoffmann 1979457215ecSHu Tao static void ohci_realize_pxa(DeviceState *dev, Error **errp) 1980f1ae32a1SGerd Hoffmann { 19811aa0c0c7SHu Tao OHCISysBusState *s = SYSBUS_OHCI(dev); 1982457215ecSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 1983f1ae32a1SGerd Hoffmann 1984f1ae32a1SGerd Hoffmann /* Cannot fail as we pass NULL for masterbus */ 1985457215ecSHu Tao usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, NULL, 0, 198687581feaSMarkus Armbruster &address_space_memory, &error_abort); 1987457215ecSHu Tao sysbus_init_irq(sbd, &s->ohci.irq); 1988457215ecSHu Tao sysbus_init_mmio(sbd, &s->ohci.mem); 1989f1ae32a1SGerd Hoffmann } 1990f1ae32a1SGerd Hoffmann 1991*88dd1b8dSGonglei static void usb_ohci_reset_sysbus(DeviceState *dev) 1992*88dd1b8dSGonglei { 1993*88dd1b8dSGonglei OHCISysBusState *s = SYSBUS_OHCI(dev); 1994*88dd1b8dSGonglei OHCIState *ohci = &s->ohci; 1995*88dd1b8dSGonglei 1996*88dd1b8dSGonglei ohci_reset(ohci); 1997*88dd1b8dSGonglei } 1998*88dd1b8dSGonglei 1999f1ae32a1SGerd Hoffmann static Property ohci_pci_properties[] = { 2000f1ae32a1SGerd Hoffmann DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), 2001f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), 2002f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), 2003f1ae32a1SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 2004f1ae32a1SGerd Hoffmann }; 2005f1ae32a1SGerd Hoffmann 200669e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_state_port = { 200769e25d26SAlexey Kardashevskiy .name = "ohci-core/port", 200869e25d26SAlexey Kardashevskiy .version_id = 1, 200969e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 201069e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 201169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl, OHCIPort), 201269e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 201369e25d26SAlexey Kardashevskiy }, 201469e25d26SAlexey Kardashevskiy }; 201569e25d26SAlexey Kardashevskiy 201669e25d26SAlexey Kardashevskiy static bool ohci_eof_timer_needed(void *opaque) 201769e25d26SAlexey Kardashevskiy { 201869e25d26SAlexey Kardashevskiy OHCIState *ohci = opaque; 201969e25d26SAlexey Kardashevskiy 202069e25d26SAlexey Kardashevskiy return ohci->eof_timer != NULL; 202169e25d26SAlexey Kardashevskiy } 202269e25d26SAlexey Kardashevskiy 202369e25d26SAlexey Kardashevskiy static int ohci_eof_timer_pre_load(void *opaque) 202469e25d26SAlexey Kardashevskiy { 202569e25d26SAlexey Kardashevskiy OHCIState *ohci = opaque; 202669e25d26SAlexey Kardashevskiy 202769e25d26SAlexey Kardashevskiy ohci_bus_start(ohci); 202869e25d26SAlexey Kardashevskiy 202969e25d26SAlexey Kardashevskiy return 0; 203069e25d26SAlexey Kardashevskiy } 203169e25d26SAlexey Kardashevskiy 203269e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_eof_timer = { 203369e25d26SAlexey Kardashevskiy .name = "ohci-core/eof-timer", 203469e25d26SAlexey Kardashevskiy .version_id = 1, 203569e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 203669e25d26SAlexey Kardashevskiy .pre_load = ohci_eof_timer_pre_load, 203769e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 2038e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(eof_timer, OHCIState), 203969e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 204069e25d26SAlexey Kardashevskiy }, 204169e25d26SAlexey Kardashevskiy }; 204269e25d26SAlexey Kardashevskiy 2043b9b45b4aSStefan Weil static const VMStateDescription vmstate_ohci_state = { 204469e25d26SAlexey Kardashevskiy .name = "ohci-core", 204569e25d26SAlexey Kardashevskiy .version_id = 1, 204669e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 204769e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 204869e25d26SAlexey Kardashevskiy VMSTATE_INT64(sof_time, OHCIState), 204969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctl, OHCIState), 205069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(status, OHCIState), 205169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr_status, OHCIState), 205269e25d26SAlexey Kardashevskiy VMSTATE_UINT32(intr, OHCIState), 205369e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hcca, OHCIState), 205469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_head, OHCIState), 205569e25d26SAlexey Kardashevskiy VMSTATE_UINT32(ctrl_cur, OHCIState), 205669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_head, OHCIState), 205769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(bulk_cur, OHCIState), 205869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(per_cur, OHCIState), 205969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(done, OHCIState), 206069e25d26SAlexey Kardashevskiy VMSTATE_INT32(done_count, OHCIState), 206169e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fsmps, OHCIState), 206269e25d26SAlexey Kardashevskiy VMSTATE_UINT8(fit, OHCIState), 206369e25d26SAlexey Kardashevskiy VMSTATE_UINT16(fi, OHCIState), 206469e25d26SAlexey Kardashevskiy VMSTATE_UINT8(frt, OHCIState), 206569e25d26SAlexey Kardashevskiy VMSTATE_UINT16(frame_number, OHCIState), 206669e25d26SAlexey Kardashevskiy VMSTATE_UINT16(padding, OHCIState), 206769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(pstart, OHCIState), 206869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(lst, OHCIState), 206969e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_a, OHCIState), 207069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhdesc_b, OHCIState), 207169e25d26SAlexey Kardashevskiy VMSTATE_UINT32(rhstatus, OHCIState), 207269e25d26SAlexey Kardashevskiy VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0, 207369e25d26SAlexey Kardashevskiy vmstate_ohci_state_port, OHCIPort), 207469e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hstatus, OHCIState), 207569e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hmask, OHCIState), 207669e25d26SAlexey Kardashevskiy VMSTATE_UINT32(hreset, OHCIState), 207769e25d26SAlexey Kardashevskiy VMSTATE_UINT32(htest, OHCIState), 207869e25d26SAlexey Kardashevskiy VMSTATE_UINT32(old_ctl, OHCIState), 207969e25d26SAlexey Kardashevskiy VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192), 208069e25d26SAlexey Kardashevskiy VMSTATE_UINT32(async_td, OHCIState), 208169e25d26SAlexey Kardashevskiy VMSTATE_BOOL(async_complete, OHCIState), 208269e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 208369e25d26SAlexey Kardashevskiy }, 208469e25d26SAlexey Kardashevskiy .subsections = (VMStateSubsection []) { 208569e25d26SAlexey Kardashevskiy { 208669e25d26SAlexey Kardashevskiy .vmsd = &vmstate_ohci_eof_timer, 208769e25d26SAlexey Kardashevskiy .needed = ohci_eof_timer_needed, 208869e25d26SAlexey Kardashevskiy } , { 208969e25d26SAlexey Kardashevskiy /* empty */ 209069e25d26SAlexey Kardashevskiy } 209169e25d26SAlexey Kardashevskiy } 209269e25d26SAlexey Kardashevskiy }; 209369e25d26SAlexey Kardashevskiy 209469e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci = { 209569e25d26SAlexey Kardashevskiy .name = "ohci", 209669e25d26SAlexey Kardashevskiy .version_id = 1, 209769e25d26SAlexey Kardashevskiy .minimum_version_id = 1, 209869e25d26SAlexey Kardashevskiy .fields = (VMStateField[]) { 209969e25d26SAlexey Kardashevskiy VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), 210069e25d26SAlexey Kardashevskiy VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState), 210169e25d26SAlexey Kardashevskiy VMSTATE_END_OF_LIST() 210269e25d26SAlexey Kardashevskiy } 210369e25d26SAlexey Kardashevskiy }; 210469e25d26SAlexey Kardashevskiy 2105f1ae32a1SGerd Hoffmann static void ohci_pci_class_init(ObjectClass *klass, void *data) 2106f1ae32a1SGerd Hoffmann { 2107f1ae32a1SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 2108f1ae32a1SGerd Hoffmann PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 2109f1ae32a1SGerd Hoffmann 211087581feaSMarkus Armbruster k->realize = usb_ohci_realize_pci; 211107832c38SGonglei k->exit = usb_ohci_exit; 2112f1ae32a1SGerd Hoffmann k->vendor_id = PCI_VENDOR_ID_APPLE; 2113f1ae32a1SGerd Hoffmann k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; 2114f1ae32a1SGerd Hoffmann k->class_id = PCI_CLASS_SERIAL_USB; 2115125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_USB, dc->categories); 2116f1ae32a1SGerd Hoffmann dc->desc = "Apple USB Controller"; 2117f1ae32a1SGerd Hoffmann dc->props = ohci_pci_properties; 21182897ae02SIgor Mammedov dc->hotpluggable = false; 211969e25d26SAlexey Kardashevskiy dc->vmsd = &vmstate_ohci; 2120*88dd1b8dSGonglei dc->reset = usb_ohci_reset_pci; 2121f1ae32a1SGerd Hoffmann } 2122f1ae32a1SGerd Hoffmann 21238c43a6f0SAndreas Färber static const TypeInfo ohci_pci_info = { 21241aa0c0c7SHu Tao .name = TYPE_PCI_OHCI, 2125f1ae32a1SGerd Hoffmann .parent = TYPE_PCI_DEVICE, 2126f1ae32a1SGerd Hoffmann .instance_size = sizeof(OHCIPCIState), 2127f1ae32a1SGerd Hoffmann .class_init = ohci_pci_class_init, 2128f1ae32a1SGerd Hoffmann }; 2129f1ae32a1SGerd Hoffmann 2130f1ae32a1SGerd Hoffmann static Property ohci_sysbus_properties[] = { 2131f1ae32a1SGerd Hoffmann DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), 21329ac6a217SDavid Gibson DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 3), 2133f1ae32a1SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 2134f1ae32a1SGerd Hoffmann }; 2135f1ae32a1SGerd Hoffmann 2136f1ae32a1SGerd Hoffmann static void ohci_sysbus_class_init(ObjectClass *klass, void *data) 2137f1ae32a1SGerd Hoffmann { 2138f1ae32a1SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 2139f1ae32a1SGerd Hoffmann 2140457215ecSHu Tao dc->realize = ohci_realize_pxa; 2141125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_USB, dc->categories); 2142f1ae32a1SGerd Hoffmann dc->desc = "OHCI USB Controller"; 2143f1ae32a1SGerd Hoffmann dc->props = ohci_sysbus_properties; 2144*88dd1b8dSGonglei dc->reset = usb_ohci_reset_sysbus; 2145f1ae32a1SGerd Hoffmann } 2146f1ae32a1SGerd Hoffmann 21478c43a6f0SAndreas Färber static const TypeInfo ohci_sysbus_info = { 21481aa0c0c7SHu Tao .name = TYPE_SYSBUS_OHCI, 2149f1ae32a1SGerd Hoffmann .parent = TYPE_SYS_BUS_DEVICE, 2150f1ae32a1SGerd Hoffmann .instance_size = sizeof(OHCISysBusState), 2151f1ae32a1SGerd Hoffmann .class_init = ohci_sysbus_class_init, 2152f1ae32a1SGerd Hoffmann }; 2153f1ae32a1SGerd Hoffmann 2154f1ae32a1SGerd Hoffmann static void ohci_register_types(void) 2155f1ae32a1SGerd Hoffmann { 2156f1ae32a1SGerd Hoffmann type_register_static(&ohci_pci_info); 2157f1ae32a1SGerd Hoffmann type_register_static(&ohci_sysbus_info); 2158f1ae32a1SGerd Hoffmann } 2159f1ae32a1SGerd Hoffmann 2160f1ae32a1SGerd Hoffmann type_init(ohci_register_types) 2161